程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#實現(遞歸和非遞歸)快速排序和簡單排序等一系列排序算法

C#實現(遞歸和非遞歸)快速排序和簡單排序等一系列排序算法

編輯:C#入門知識

本人因為最近工作用到了一些排序算法,就把幾個簡單的排序算法,想冒泡排序,選擇排序,插入排序,奇偶排序和快速排序等整理了出來,代碼用C#代碼實現,並且通過了測試。希望能給大家提供參考。

1.冒泡排序

冒泡排序,是指計算機的一種排序算法,它的時間復雜度是O(n^2),雖然不及堆排序和快速排序時間復雜度為O(nlogn,底數為2),但是有兩個優點:1:編程復雜度低,很容易實現;2 是具有穩定性,這裡的穩定性是指源序列中相同元素的相對順序仍然保持到排序後的順序,而堆排序和快速排序都不具有穩定性。

基本概念

冒泡排序(BubbleSort)的基本概念:依次比較相鄰兩個數,小的在前,大的在後。在第一趟,首先比較第1個數和第2個數,小的放在前面,大的放在後面,然後比較第2個數和第3個數,小的在前,大的在後,如此繼續,直到比較最後兩個數,小的在前,大的在後,第一趟結束時,就把最大的數放在了最後。在第二趟,仍從第一對數開始比較(因為由於第2個數和第3個數的交換,使第1個數不再小於第2個數),將小數放前,大數放後,一直比較到倒數第二個數(倒數第一個數已經是最大的),第二趟結束,這樣在倒數第二個位置得到一個新的最大數,如此循環下去,重復以上過程,直至最終完成排序。

比如有一個數列10, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76

第一次排序後:10,2,4,33,6,12,34,55,66,43,23,65,1,345,61,76,31,43,76,456

第二次排序後:2,4,10,6,12,33,34,55,43,23,65,1,66,61,76,31,43,76,345,456

第三次排序後:2,4,6,10,12,33,34,43,23,55,1,65,61,66,31,43,76,76,345,456

第四次排序後:2,4,6,10,12,33,34,23,43,1,55,61,65,31,43,66,76,76,345,456

第五次排序後: 2,4,6,10,12,33,23,34,1,43,55,61,31,43,65,66,76,76,345,456

第六次排序後: 2,4,6,10,12,23,33,1,34,43,55,31,43,61,65,66,76,76,345,456

第七次排序後: 2,4,6,10,12,23,1,33,34,43,31,43,55,61,65,66,76,76,345,456

第八次排序後: 2,4,6,10,12,1,23,33,34,31,43,43,55,61,65,66,76,76,345,456

第九次排序後: 2,4,6,10,1,12,23,33,31,34,43,43,55,61,65,66,76,76,345,456

第十次排序後: 2,4,6,1,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

第十一次排序後:2,4,1,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

第十二次排序後:2,1,4,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

第十三次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

這樣經過13趟排序後這個序列就成為一個有序的數列。

具體實現代碼為:

private static void BubbleSort(int[] R)
{
int len = R.Length;
bool flag = false;
for (int i = 0; i < len-1; i++)
{
flag = false;
for (int j = 0; j < len - i-1; j++)
{
if (R[j] > R[j + 1])
{
Swap(ref R[j], ref R[j + 1]);
flag = true;
}
}
if (!flag)
{
break;
}
}
}

private static void Swap(ref int left, ref int right)
{
int temp = left;
left = right;
right = temp;
}

2. 選擇排序

每一趟從待排序的元素中選擇最小的(最大的)一個元素,順序放在已排好序的數列的最後,直到待排序的元素派完,選擇排序是不穩定的排序。

基本概念

具有n元素的數列可以進行n-1趟直接選擇排序得到有序結果,初始狀態有序區為空,無序區為R[1...n]

第1趟排序在無序區R[1...n]選擇關鍵字最小的元素R[k],將它與無序區的R[1] 進行交換,使R[1...1]和R[2...n]變為個增加為1新有序區,和無序區的元素個數減去1的新無序區。

第i趟排序開始時,當前有序區和無序區分別為R[1..i-1]和R(1≤i≤n-1)。該趟排序從當前無序區中選出關鍵字最小的記錄 R[k],將它與無序區的第1個記錄R交換,

使R[1..i]和R分別變 為記錄個數增加1個的新有序區和記錄個數減少1個的新無序區。 這樣,n個記錄的文件的直接選擇排序可經過n-1趟直接選擇排序得到有序結果 .

對於數列 10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76

第一次排序後:1,33,2,4,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76

第二次排序後: 1,2,33,4,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76

第三次排序後:1,2,4,33,55,6,12,34,456,66,43,23,65,10,345,61,76,31,43,76

第四次排序後:1,2,4,6,55,33,12,34,456,66,43,23,65,10,345,61,76,31,43,76

第五次排序後:1,2,4,6,10,33,12,34,456,66,43,23,65,55,345,61,76,31,43,76

第六次排序後: 1,2,4,6,10,12,33,34,456,66,43,23,65,55,345,61,76,31,43,76

第七次排序後: 1,2,4,6,10,12,23,34,456,66,43,33,65,55,345,61,76,31,43,76

第八次排序後: 1,2,4,6,10,12,23,31,456,66,43,33,65,55,345,71,76,34,43,76

第九次排序後: 1,2,4,6,10,12,23,31,33,66,43,456,65,55,345,71,76,34,43,76

第十次排序後: 1,2,4,6,10,12,23,31,33,34,43,456,65,55,345,71,76,66,43,76

第十一次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,65,55,345,71,76,66,456,76

第十二次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,345,71,76,66,456,76

第十三次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,345,456,76

第十四次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,76,456,345

第十五次排序後: 1,2,4,6,10,12,23,31,33,34,43,43,55,65,66,71,76,76,345,456

最終經過15次排序後成為有序的數列。

具體實現代碼為:

private static void SelectSort(int[] R)
{
int len = R.Length;
int min = 0;
for (int i = 0; i < len - 1; i++)
{
min = i;
for (int j = i + 1; j < len - 1; j++)
{
if (R[min] > R[j])
{
min = j;
}
}
Swap(ref R[i], ref R[min]);
}
}

3. 插入排序

插入排序算法是一種穩定的算法,時間復雜度是O(n^2),適用於少量數據的排序。插入算法的基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的,個數加1的有序數據。插入算法把要排序的數組分為兩部分:第一部分包含了數組的所有元素,但將最後一個元素除外,而第二部分就只包含這一個元素,在第一部分排序後,再把最後這個元素插入到此刻已是有序的一部分中。

基本思想

1:每次處理都是將無序序列的第一個元素和有序序列的元素從後面逐一比較,查到合適的插入位置,將該元素插入到有序序列的合適位置。

2:從有序R[1]和無序R[2...n]開始進行排序。

3:處理第i個元素時(i=2,3,…,n) ,數列{R1,R2,...Ri-1}都是有序的,而數列{Ri,Ri+1,...Rn}都是無序的,用Ri 與{R1,R2,...Ri-1}逐個比較,找到合適位置,將Ri插入,

4:重復第三部,共進行n-i次插入處理,數組全部有序

對於數列 10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76

第一次排序後:10,33,2,4,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

第二次排序後: 2,10,33,4,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

第三次排序後: 2,4,10,33,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

第四次排序後: 2,4,10,33,55,12,34,456,66,43,23,65,1,345,61,76,31,43,76

第五次排序後: 2,3,10,12,33,55,34,456,66,43,23,65,1,345,61,76,31,43,76

第六次排序後: 2,3,10,12,33,34,55,456,66,43,23,65,1,345,61,76,31,43,76

第七次排序後: 2,3,10,12,33,34,55,456,66,43,23,65,1,345,61,76,31,43,76

第八次排序後: 2,3,10,12,33,34,55,66,456,43,23,65,1,345,61,76,31,43,76

第九次排序後: 2,3,10,12,33,34,43,55,66,456,23,65,1,345,61,76,31,43,76

第十次排序後: 2,3,10,12,23,33,34,43,55,66,456,65,1,345,61,76,31,43,76

第十一次排序後: 2,3,10,12,23,33,34,43,55,65,66,456,1,345,61,76,31,43,76

第十二次排序後: 1,2,3,10,12,23,33,34,43,55,65,66,456,345,61,76,31,43,76

第十三次排序後: 1,2,3,10,12,23,33,34,43,55,65,66,345,456,61,76,31,43,76

第十四次排序後: 1,2,3,10,12,23,33,34,43,55,61,65,66,345,456,76,31,43,76

第十五次排序後: 1,2,3,10,12,23,33,34,43,55,61,65,66,76,345,456,31,43,76

第十六次排序後: 1,2,3,10,12,23,31,33,34,43,55,61,65,66,76,345,456,43,76

第十七次排序後: 1,2,3,10,12,23,31,33,34,43,43,55,61,65,66,76,345,456,76

第十八次排序後: 1,2,3,10,12,23,31,33,34,43,43,55,61,65,66,76,76,345,456

共十八次排序後,數組才是全部有序的。

實現代碼為:

private static void InsertSort(int[] R)
{
int len = R.Length;
int j = 0;
int temp = 0;
for (int i = 1; i < len; i++)
{
temp=R[i];
j=i-1;
while (j >= 0 && temp < R[j])
{
R[j + 1] = R[j];
j--;
}
R[j + 1] = temp;
}
}

4. 快速排序

快速排序是對冒泡排序的一種改進,它的基本思想是:通過一趟排序將要排序的數列分成獨立的兩個部分,其中一部分的所有數據都比後一部分的所有數據都要小,然後再按此方法對這兩個部分分別進行快速排序,整個排序過程可以遞歸進行,以次達到整個數列變為有序。快速排序不是穩定的排序。

算法過程

設要排序的數組為R[1...n],首先任意選取一個元素(通常選擇第一個元素)作為關鍵元素,然後把所有比它小的都放在前面,所有比它大的都放在後面,這個過程成為一趟快速排序。

1. 設置兩個變量 low ,high,排序開始的時候low=0,high=n-1;

2. 以第一個數組元素為關鍵數據key,即key = R[low];

3. 從high開始往前搜索,即由後開始向前搜索,high=high-1,找到第一個小於key的值R[high], 並與R[low] 交換,

4. 從low 開始向後搜索,即由前開始向後搜索,low=low+1,找到第一個大於key的值R[low],並於R[high]交換。

5. 重復3,4.直到low=high.

對於數列 10,33,2,4,55,6,12,34,456,66,43,23,65,1,345, 61,76,31,43,76

初始關鍵數據key=10;

第一次交換後:1, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76

第二次交換後: 1, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76

第三次交換後: 1, 6, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76

第四次交換後: 1, 6, 2, 4, 55, 55, 12, 34, 456, 66, 43, 23, 65, 33, 345, 61, 76, 31, 43, 76

這樣low=high=4

再把R[low]=key

這樣第一次快速排序後數列就變為{1,6,2,4}10{55,12,34,456,66,43,23,65,33,345,61,76,31,43,76}

這樣再分別對{1,6,2,4}和{55,12,34,456,66,43,23,65,33,345,61,76,31,43,76} 分別進行快速排序,重復這個步驟,最終使整個數組都是有序的。

具體實現代碼為:

private static void QuickSort(int[] R, int low, int high)
{
int pivotLoc = 0;

if(low

{
pivotLoc = Partition(R, low, high);
QuickSort(R, low, pivotLoc - 1);
QuickSort(R, pivotLoc + 1, high);

}
}

private static int Partition(int[] R, int low, int high)
{
int temp = R[low];
while (low < high)
{
while (low < high && temp <= R[high])
{
high--;
}
R[low] = R[high];
while (low < high && temp >= R[low])
{
low++;
}
R[high] = R[low];
}
R[low] = temp;
return low;
}

//快速非遞歸排序
public static void QuickSort(int[] R, int Low, int High, Stack stack)
{
int low = Low;
int high = High;
int temp = R[low];
while (high > low)
{
while (low < high && temp <= R[high])
{
high--;
}
if (high > low)
{
R[low] = R[high];
R[high] = temp;
}
while (low < high && temp >= R[low])
{
low++;
}
if (high > low)
{
R[high] = R[low];
R[low] = temp;
}
if (low == high)
{
if (Low < low - 1)
{
stack.Push(Low);
stack.Push(low - 1);
}
if (High > low + 1)
{
stack.Push(low + 1);
stack.Push(High);
}
}
}
}

測試代碼:

static void Main(string[] args)

{

int[] arry = new int[] { 10, 33, 2, 4, 55, 6, 12, 34, 456, 66, 43, 23, 65, 1, 345, 61, 76, 31, 43, 76 };
Stack s=new Stack();
s.Push(0);
s.Push(arryk.Length - 1);
while (s.Count > 0)
{
int low = s.Pop();
int high = s.Pop();
if (low > high)
{
temp = low;
low = high;
high = temp;
}
QuickSort(arryk, low, high, s);
}
Console.ReadLine();

}

通過對10萬條隨機數據進行遞歸和非遞歸排序後發現,非遞歸方法的速度是遞歸方法速度的40倍左右。

5 . 一個無序的數組,如何通過一個函數取出最大值和最小值,要求時間復雜度最低和空間最少

具體算法如下:

private static int[] GetMaxMin(int[] R)
{
int len=R.Length;
int min = R[0];
int max = R[0];
for (int i = 1; i < len;i++ )
{
if (min > R[i])
{
min = R[i];
}
if (max < R[i])
{
max = R[i];
}
}
int[] res = new int[2];
res[0] = min;
res[1] = max;
return res;

}
6 對於已知數組,隨機存儲一百個數,把奇數放左邊,偶數放右邊,具體算法如下:

private static void SortNumber(int[] R)
{
int high = R.Length - 1;
int low = 0;
int temp = R[low];
while (low < high)
{
while(low {
high--;
}
R[low] = R[high];
while (low < high && R[low] % 2 == 1)
{
low++;
}
R[high] = R[low];
}
R[low] = temp;
}

7.二分查找算法

二分查找算法又叫折半查找,優點是比較次數少,查找速度快,平均性能好,缺點是給定的數組必須是有序的,且插入刪除困難,因此二分查找使用與不經常變動而又查找頻繁的有序表。 首先,假設數組是按照升序的有序表,將表中間位置的元素與給定要查找的元素比較,如果相等,則查找成功,否則利用中間位置將表分為前後兩個字表,如果中間位置記錄的元素大於給定的查找的數據,在前面的字表中進行查找,否則在後面的字表中進行查找。重復以上過程,直到找到或沒有子表為止。

具體實現代碼如下:

private static int BinarySearch(int[] R, int arg)
{
int low = 0;
int high = R.Length - 1;
while (low < high)
{
int middle = (low + high) / 2;
if (arg == R[middle])
{
return middle;
}
else if (arg < R[middle])
{
high = middle - 1;
}
else
{
low = middle + 1;
}
}
return -1;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved