前言:算法
排序算法是咱們編程中遇到的最多的算法。目前主流的算法有8種。編程
平均時間複雜度從高到低依次是:數組
冒泡排序(o(n2)),選擇排序(o(n2)),插入排序(o(n2)),堆排序(o(nlogn)),測試
歸併排序(o(nlogn)),快速排序(o(nlogn)), 希爾排序(o(n1.25)),基數排序(o(n))優化
申明:如下排序所有針對數組{ 25, 1, 5, 2, 9, 11, 2, 4 }; 全部測試使用備註,只是爲了讓用戶根據結果看得更加明白,理解以後可刪除。ui
1、冒泡排序:spa
思想:從數組第一位開始,每一個元素和它下一位比較,將大的換到後面,即每一輪循環以後能夠肯定一個位置。提升效率(可定義一個標記,若是一輪循環以後沒有發生交換直接結束).net
代碼:3d
static void maopao() { int[] a = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; bool sign = false; for (int i = 0; i < a.Length - 1; i++) { for (int j = 0; j < a.Length - i - 1; j++) { if (a[j] > a[j+1]) { outPuts(a, "交換以前");//測試使用 Console.Write(String.Format(" {0:D2}<-交換->{1:D2} ", a[j], a[j + 1]));//測試使用 int b = a[j]; a[j] = a[j + 1]; a[j + 1] = b; sign = true; outPuts(a, "交換以後");//測試使用 Console.WriteLine();//測試使用 } } if (!sign) break; } Console.WriteLine();//測試使用 outPuts(a, "最後數據"); Console.ReadKey(); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
結果:指針
2、選擇排序:
對冒泡排序進行優化,由上結果能夠看到25連續交換屢次,那麼如何實現一次循環只交換一次就能夠肯定一個位置呢?
思想:對於第一趟,搜索整個數組,尋找出最小(或最大此處以最小爲例即從小到大排序)的,而後放置在數組的0號位置;對於第二趟,搜索數組的n-1個記錄,尋找出最小的(對於整個數組來講則是次小的),而後放置到數組的第1號位置。在第i趟時,搜索數組的n-i+1個記錄,尋找最小的記錄(對於整個數組來講則是第i小的),而後放在數組i-1的位置(注意數組以0起始)。
代碼:
private static void xuanze() { int[] a = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; for (int i = 0; i < a.Length - 1; i++) { int sign = i; for (int j = i + 1; j < a.Length; j++) { if (a[sign] > a[j]) { sign = j; } } if (sign != i) { outPuts(a, "交換以前");//測試使用 Console.Write(String.Format(" {0:D2}<-交換->{1:D2} ", a[i], a[sign]));//測試使用 int b = a[i]; a[i] = a[sign]; a[sign] = b; outPuts(a, "交換以後");//測試使用 Console.WriteLine();//測試使用 } } Console.WriteLine();//測試使用 outPuts(a, "最後數據"); Console.ReadKey(); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
結果:
3、插入排序:
插入排序是一種對於有序數列高效的排序。很是聰明的排序。只是對於隨機數列,效率通常,交換的頻率高。
思想:數組下標1開始,和前面下標爲0的數據做比較,若是下標0的數據大於(或小於即從大到小排序)下標1的數據則後移,下標1的數據插入到0的位置,不然插入當前位置。數組下標m開始,和因此前面數據做比較,即下標爲n(m-1>=n>=0)的數據做比較,若是下標n的數據大於(或小於即從大到小排序)下標m的數據則後移,直到n=-1,將下標爲m獲得數據插入到下標爲0的位置,不然插入當前位置,
代碼:
private static void charu() { int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; for (int i = 1; i < data.Length; i++) { int d = data[i]; bool result = true;//標記,表示已經比較到第一個位置 for (int j = i - 1; j >= 0; j--) { if (data[j] > d) { outPuts(data, "移動以前");//測試使用 Console.Write(String.Format(" 從下標{0}開始 {1}<-移動->{2} ",i, j, j+1));//測試使用 data[j + 1] = data[j]; outPuts(data, "移動以後");//測試使用 Console.WriteLine();//測試使用 } else { outPuts(data, "插入以前");//測試使用 Console.Write(String.Format(" 從下標{0}開始 數據{1}<-插入到->{2} ", i, d, j + 1));//測試使用 data[j + 1] = d; result = false; outPuts(data, "插入以後");//測試使用 Console.WriteLine();//測試使用 break; } } if (result) { outPuts(data, "插入以前");//測試使用 Console.Write(String.Format(" 數據{0}<-插入到->{1} ", d, 0));//測試使用 data[0] = d; outPuts(data, "插入以後");//測試使用 Console.WriteLine();//測試使用 } } Console.WriteLine();//測試使用 outPuts(data, "最後數據"); Console.ReadKey(); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
//方法二 private static void charu2(int[] data) { int j; for (int i = 1; i < data.Length; i++) { int d = data[i]; for (j = i - 1; j >= 0 && data[j] > d; j--) { data[j + 1] = data[j]; } data[j + 1] = d; } }
結果:
4、快速排序:
快速排序是一種高效排序。它包含了「分而治之」以及「哨兵」的思想。
思想:從數組中挑選一個數(通常爲第一個數據)做爲「哨兵」,使比它小的放在它的左側,比它大的放在它的右側。
說明:25爲哨兵,定義變量保存,0位置爲待處理位置,從right向前找直到找到比哨兵小的,將其放入到待處理位置,left++,並設置當前爲待處理位置,從left開始向後找比哨兵大的放入待處理位置,right--,並設置當前爲待處理位置。直到left>right結束,此時第一個哨兵位置肯定。並以哨兵爲點,將數組分爲兩段分別繼續遞歸實現該方法。
代碼:
private static void kuaisu(int[] data, int left, int right) { if (left >= right) return; int x = data[left]; int i = left; int j = right; try { while (i < j) { while (i < j && data[j] >= x) { j--; } if (i == j) break; outPuts(data, "移動以前");//測試使用 Console.Write(String.Format(" {0}<-移動到->{1} ", j, i));//測試使用 data[i++] = data[j]; outPuts(data, "移動以後");//測試使用 Console.WriteLine();//測試使用 while (i < j && data[i] <= x) { i++; } if (i == j) break; outPuts(data, "移動以前");//測試使用 Console.Write(String.Format(" {0}<-移動到->{1} ", i, j));//測試使用 data[j--] = data[i]; outPuts(data, "移動以後");//測試使用 Console.WriteLine();//測試使用 } outPuts(data, "移動以前");//測試使用 Console.Write(String.Format(" 數據{0}<-移動到->{1} 數據區間{2}--{3} ", x, i,left,right));//測試使用 data[i] = x; outPuts(data, "移動以後");//測試使用 Console.WriteLine();//測試使用 kuaisu(data, left, i - 1); kuaisu(data, i + 1, right); } catch (Exception e) { Console.WriteLine(e); } } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
結果:
5、歸併排序:
使用遞歸方法。
思想:將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。
那麼如何肯定一個子序列有序呢?固然子序列個數爲1時天然有序。因此將數組分爲兩段,一直分段遞歸下去,直到數組長度爲1返回,此時將其歸併直到結束。
歸併操做的工做原理以下:
第一步:申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
第二步:設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
重複步驟3直到某一指針超出序列尾
將另外一序列剩下的全部元素直接複製到合併序列尾
代碼:
int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; guibing(data, 0, data.Length - 1); outPuts(data, "最後數據"); Console.ReadKey();
private static void guibing(int[] data, int left, int right) { if (left < right) { int mid = (left + right) / 2; guibing(data, left, mid); guibing(data, mid + 1, right); arrayAdd(data, left, mid, right); } } private static void arrayAdd(int[] data, int left, int mid, int right) { int[] d = new int[right - left + 1]; int i = left; int j = mid + 1; int k = 0; while (i <= mid && j <= right) { if (data[j] < data[i]) d[k++] = data[j++]; else d[k++] = data[i++]; } while (i <= mid) { d[k++] = data[i++]; } while (j <= right) { d[k++] = data[j++]; } i = left; for (k = 0; k < d.Length; k++) { outPuts(data, "賦值以前");//測試使用 Console.Write(" ");//測試使用 data[i++] = d[k]; outPuts(data, "賦值以後");//測試使用 Console.Write(String.Format(" 賦值下標位置範圍{0}--{1} 臨時數組:",left,right));//測試使用 foreach (int f in d) //測試使用 { Console.Write(f + " "); } Console.WriteLine();//測試使用 } } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
結果:
6、希爾排序:
希爾排序是插入排序的一種更高效的改進版本。
思想:希爾排序是把記錄按下標的必定增量分組,對每組使用直接插入排序算法排序,隨着增量逐漸減小,每組包含的關鍵詞愈來愈多,當增量減至1時,整個數列恰被分紅一組,算法便終止。
增量算法有:http://www.javashuo.com/article/p-bhzgywko-bv.html
本文以:Hibbard 增量序列爲例
代碼:
int[] data = new int[] { 25, 1, 5, 2, 9, 11, 2, 4 }; xier(data);
private static void xier(int[] data) { List<int> garArry = new List<int>(); int m = 0; while (Math.Pow(2,m) - 1 <= data.Length / 2) { m++; garArry.Add((int)Math.Pow(2, m) - 1); } for (int y = garArry.Count - 1; y >= 0; y--) { int gap = garArry[y]; int j; //比較次數 for (int i = gap; i < data.Length; i++) { int d = data[i]; for (j = i - gap; j >= 0 && data[j] > d; j -= gap) { outPuts(data, "移動以前");//測試使用 Console.Write(String.Format(" {0}<-移動到->{1} 步長{2} ", j, j + gap, gap));//測試使用 data[j + gap] = data[j]; outPuts(data, "移動以後");//測試使用 Console.WriteLine();//測試使用 } outPuts(data, "移動以前");//測試使用 Console.Write(String.Format(" 數據{0}<-移動到->{1} 步長{2} ", d, j + gap, gap));//測試使用 data[j + gap] = d; outPuts(data, "移動以後");//測試使用 Console.WriteLine();//測試使用 } } outPuts(data, "最後數據"); } private static void outPuts(int[] a, string str) { Console.Write(str + ":"); foreach (var item in a) { Console.Write(item + " "); } }
結果:
後續添加更多排序方法