本文盡量用簡單直白通俗易懂深入淺出詳實通透的手法將常見的幾種排序算法的原理和代碼呈現給眾位,歡迎批評指教!
為簡單起見,本文所述排序默認都以升序排序為例。(當然最后給出的源代碼是升序降序都有的)
冒泡排序(Bubble sort)
冒泡排序每輪都得到數列中的最大值,同時將其置於最后,然后對剩余部分進行排序。

1 /// <summary> 2 /// 當某輪比較沒有發生移動時,就可以確定排序完成了 3 /// <para>穩定排序</para> 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="arr"></param> 7 private static void BubbleSortAscending1<T>(this IList<T> arr) 8 where T : IComparable 9 { 10 bool exchanges; 11 do 12 { 13 exchanges = false; 14 for (int i = 0; i < arr.Count - 1; i++) 15 { 16 if (arr[i].CompareTo(arr[i + 1]) > 0) 17 { 18 T temp = arr[i]; 19 arr[i] = arr[i + 1]; 20 arr[i + 1] = temp; 21 //當某輪比較沒有發生移動時,就可以確定排序完成了 22 //否則應該繼續排序 23 exchanges = true; 24 } 25 } 26 } while (exchanges); 27 }
堆排序(Heap sort)
堆排序總是建立這樣一個二叉樹:其父結點總大於其子結點。
首先建堆。
每輪將根結點與最后一個結點互換,然后對剩余部分建堆。

1 private static void HeapSortAscending1<T>(this IList<T> arr) 2 where T : IComparable 3 { 4 for (int i = arr.Count / 2 - 1; i >= 0; i--) 5 { 6 arr.HeapAdjustAscending1(i, arr.Count); 7 } 8 for (int i = arr.Count - 1; i > 0; i--) 9 { 10 T temp = arr[0]; 11 arr[0] = arr[i]; 12 arr[i] = temp; 13 arr.HeapAdjustAscending1(0, i); 14 } 15 } 16 private static void HeapAdjustAscending1<T>(this IList<T> arr, int nonLeafNodeToBeAdjusted, int unRangedCount) 17 where T:IComparable 18 { 19 int leftChild = nonLeafNodeToBeAdjusted * 2 + 1; 20 int rightChild = nonLeafNodeToBeAdjusted * 2 + 2; 21 int max = nonLeafNodeToBeAdjusted; 22 if (nonLeafNodeToBeAdjusted < unRangedCount / 2) // 是非葉節點 23 { 24 if (leftChild < unRangedCount && arr[leftChild].CompareTo(arr[max]) > 0) 25 { max = leftChild; } 26 if (rightChild < unRangedCount && arr[rightChild].CompareTo(arr[max]) > 0) 27 { max = rightChild; } 28 if (max!=nonLeafNodeToBeAdjusted) 29 { 30 T temp = arr[max]; 31 arr[max] = arr[nonLeafNodeToBeAdjusted]; 32 arr[nonLeafNodeToBeAdjusted] = temp; 33 arr.HeapAdjustAscending1(max, unRangedCount); 34 } 35 } 36 }
插入排序(Insertion sort)
每輪將數列未排序部分的第一個數字插入已排好的部分。

1 /// <summary> 2 /// 插入排序算法 3 /// <para>穩定排序</para> 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="arr"></param> 7 private static void InsertionSortAscending1<T>(this IList<T> arr) 8 where T : IComparable 9 { 10 for (int i = 1; i < arr.Count; i++) 11 { 12 T temp = arr[i]; 13 int j = i; 14 while ((j > 0) && (temp.CompareTo(arr[j - 1]) < 0)) 15 { 16 arr[j] = arr[j - 1]; 17 j--; 18 } 19 arr[j] = temp; 20 } 21 }
歸並排序(Merge sort)
遞歸方法。將數列均分為前后兩部分,分別對其進行歸並排序,然后將分別完成排序的前后兩部分歸並。

1 /// <summary> 2 /// 歸並排序,自頂向下的方法 3 /// <para>穩定排序</para> 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="arr"></param> 7 private static void MergeSortAscending1<T>(this IList<T> arr) 8 where T : IComparable 9 { 10 MergeSortAscending1_Split(arr, 0, arr.Count - 1); 11 } 12 private static void MergeSortAscending1_Split<T>(IList<T> arr, int first, int last) 13 where T : IComparable 14 { 15 if (first < last) 16 { 17 int mid = (first + last) / 2; 18 MergeSortAscending1_Split(arr, first, mid); 19 MergeSortAscending1_Split(arr, mid + 1, last); 20 MergeSortAscending1_Combine(arr, first, mid, last); 21 } 22 } 23 /// <summary> 24 /// 將兩個有序的左右子表(以mid區分),合並成一個有序的表 25 /// </summary> 26 /// <typeparam name="T"></typeparam> 27 /// <param name="arr"></param> 28 /// <param name="first"></param> 29 /// <param name="mid"></param> 30 /// <param name="last"></param> 31 private static void MergeSortAscending1_Combine<T>(IList<T> arr, int first, int mid, int last) 32 where T : IComparable 33 { 34 int indexA = first;//左側子表的起始位置 35 int indexB = mid + 1;//右側子表的起始位置 36 //聲明數組(暫存左右子表的所有有序數列) 37 //長度等於左右子表的長度之和。 38 IList<T> tempList = new List<T>(arr.AsEnumerable()); 39 40 int tempIndex = 0; 41 //進行左右子表的遍歷,如果其中有一個子表遍歷完,則跳出循環 42 while (indexA <= mid && indexB <= last) 43 { 44 //此時左子表的數 <= 右子表的數 45 if (arr[indexA].CompareTo(arr[indexB]) <= 0) 46 {//將左子表的數放入暫存數組中,遍歷左子表下標++ 47 tempList[tempIndex++] = arr[indexA++]; 48 } 49 else//此時左子表的數 > 右子表的數 50 {//將右子表的數放入暫存數組中,遍歷右子表下標++ 51 tempList[tempIndex++] = arr[indexB++]; 52 } 53 } 54 //有一側子表遍歷完后,跳出循環, 55 //將另外一側子表剩下的數一次放入暫存數組中(有序) 56 while (indexA <= mid) 57 { 58 tempList[tempIndex++] = arr[indexA++]; 59 } 60 while (indexB <= last) 61 { 62 tempList[tempIndex++] = arr[indexB++]; 63 } 64 //將暫存數組中有序的數列寫入目標數組的指定位置, 65 //使進行歸並的數組段有序 66 tempIndex = 0; 67 for (int i = first; i <= last; i++) 68 { 69 arr[i] = tempList[tempIndex++]; 70 } 71 }
快速排序(Quick sort)
選擇一個數(比如第一個),依次右、左、右、左地將它右側比它小的與之互換,將它左側比它大的與之互換,最后這個數就排好了。
分別對這個數左右兩部分進行快速排序。

1 /// <summary> 2 /// 快速排序算法 3 /// <para>不穩定排序</para> 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="arr"></param> 7 private static void QuickSortAscending1<T>(this IList<T> arr) 8 where T : IComparable 9 { 10 QuickSortAscending1_Do(arr, 0, 0, arr.Count - 1); 11 } 12 private static void QuickSortAscending1_Do<T>(IList<T> arr, int indexOfRightPlaceToFind, int first, int last) 13 where T : IComparable 14 { 15 if (first < last) 16 { 17 int rightPlace = QuickSortAscending1_Find(indexOfRightPlaceToFind, arr, first, last); 18 if (first + 1 < last) 19 { 20 QuickSortAscending1_Do(arr, first, first, rightPlace - 1); 21 QuickSortAscending1_Do(arr, rightPlace + 1, rightPlace + 1, last); 22 } 23 } 24 } 25 private static int QuickSortAscending1_Find<T>(int indexOfRightPlaceToFind, IList<T> arr, int first, int last) 26 where T : IComparable 27 { 28 bool searchRight = true; 29 int indexOfLeftSearch = first; 30 int indexOfRightSearch = last; 31 do 32 { 33 if (searchRight) 34 { 35 while (arr[indexOfRightPlaceToFind].CompareTo(arr[indexOfRightSearch]) <= 0) 36 { 37 indexOfRightSearch--; 38 if (indexOfRightPlaceToFind == indexOfRightSearch) 39 { 40 searchRight = false; 41 break; 42 } 43 } 44 if (searchRight) 45 { 46 T temp = arr[indexOfRightPlaceToFind]; 47 arr[indexOfRightPlaceToFind] = arr[indexOfRightSearch]; 48 arr[indexOfRightSearch] = temp; 49 indexOfRightPlaceToFind = indexOfRightSearch; 50 searchRight = false; 51 } 52 } 53 else 54 { 55 while (arr[indexOfRightPlaceToFind].CompareTo(arr[indexOfLeftSearch]) >= 0) 56 { 57 indexOfLeftSearch++; 58 if (indexOfRightPlaceToFind == indexOfLeftSearch) 59 { 60 searchRight = true; 61 break; 62 } 63 } 64 if (!searchRight) 65 { 66 T temp = arr[indexOfRightPlaceToFind]; 67 arr[indexOfRightPlaceToFind] = arr[indexOfLeftSearch]; 68 arr[indexOfLeftSearch] = temp; 69 indexOfRightPlaceToFind = indexOfLeftSearch; 70 searchRight = true; 71 } 72 } 73 } while (indexOfLeftSearch < indexOfRightPlaceToFind || indexOfRightPlaceToFind < indexOfRightSearch); 74 return indexOfRightPlaceToFind; 75 }
選擇排序(Selection sort)
每輪找到最小的數,與未排序部分的第一個互換。

1 /// <summary> 2 /// 選擇排序算法 3 /// <para>不穩定排序</para> 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="arr"></param> 7 private static void SelectionSortAscending1<T>(this IList<T> arr) 8 where T : IComparable 9 { 10 for (int i = 0; i < arr.Count - 1; i++) 11 { 12 int min = i; 13 for (int j = i + 1; j < arr.Count; j++) 14 { 15 if (arr[j].CompareTo(arr[min]) < 0) 16 { 17 min = j; 18 } 19 } 20 if (min != i) 21 { 22 T temp = arr[i]; 23 arr[i] = arr[min]; 24 arr[min] = temp; 25 } 26 } 27 }
希爾排序(Shell sort)
縮小增量法。從大到1設置一系列增量,將序號之差等於增量的數字進行之間插入排序。

1 /// <summary> 2 /// 希爾排序算法 3 /// <para>不穩定排序</para> 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="arr"></param> 7 private static void ShellSortAscending1<T>(this IList<T> arr) 8 where T : IComparable 9 { 10 int inc; 11 for (inc = 1; inc <= arr.Count / 9; inc = 3 * inc + 1) ; 12 for (; inc > 0; inc /= 3) 13 { 14 for (int i = inc + 1; i <= arr.Count; i += inc) 15 { 16 T temp = arr[i - 1]; 17 int j = i; 18 while ((j > inc) && (temp.CompareTo(arr[j - inc - 1]) < 0)) 19 { 20 arr[j - 1] = arr[j - inc - 1]; 21 j -= inc; 22 } 23 arr[j - 1] = temp; 24 } 25 } 26 }
為了使用方便,我用如下的方式進行包裝,這樣就盡可能多的自動成為了可排序類型的擴展方法,並且不需要寫 "using ...;"之類的東西,只需引用此類庫就行了。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Collections; 6 7 namespace System 8 { 9 /// <summary> 10 /// 冒泡排序算法 11 /// <para>穩定排序</para> 12 /// </summary> 13 public static partial class _BubbleSort 14 { 15 /// <summary> 16 /// 冒泡排序(降序) 17 /// 請勿傳null給本函數,否則將發生異常 18 /// <para>穩定排序</para> 19 /// <para>冒泡排序(降序)原理:</para> 20 /// <para>從左到右以此比較兩個相鄰的數,若左小右大順序則交換一下。</para> 21 /// <para>這樣,當一輪比較結束,最小的數就排在了最右邊。</para> 22 /// <para>下一輪比較前N-1個數即可。</para> 23 /// <para>經過N-1輪比較,數列就是大->小排序的了。</para> 24 /// <para>改進的冒泡排序:當某輪比較沒有發生移動時,就可以確定排序完成了,從而減少了排序的輪數。</para> 25 /// </summary> 26 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 27 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 28 public static void BubbleSort<T>(this IList<T> arr) 29 where T : IComparable 30 { 31 arr.BubbleSortDescending(); 32 } 33 /// <summary> 34 /// 冒泡排序 35 /// 請勿傳null給本函數,否則將發生異常 36 /// <para>穩定排序</para> 37 /// <para>冒泡排序(降序)原理:</para> 38 /// <para>從左到右以此比較兩個相鄰的數,若左小右大順序則交換一下。</para> 39 /// <para>這樣,當一輪比較結束,最小的數就排在了最右邊。</para> 40 /// <para>下一輪比較前N-1個數即可。</para> 41 /// <para>經過N-1輪比較,數列就是大->小排序的了。</para> 42 /// <para>改進的冒泡排序:當某輪比較沒有發生移動時,就可以確定排序完成了,從而減少了排序的輪數。</para> 43 /// </summary> 44 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 45 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 46 /// <param name="descending">true為降序排序,false為升序排序</param> 47 public static void BubbleSort<T>(this IList<T> arr, bool descending) 48 where T : IComparable 49 { 50 if (descending) 51 arr.BubbleSortDescending(); 52 else 53 arr.BubbleSortAscending(); 54 } 55 } 56 /// <summary> 57 /// 插入排序算法 58 /// <para>穩定排序</para> 59 /// </summary> 60 public static partial class _InsertionSort 61 { 62 /// <summary> 63 /// 插入排序(降序) 64 /// 請勿傳null給本函數,否則將發生異常 65 /// <para>穩定排序</para> 66 /// <para>插入排序(降序)原理:</para> 67 /// <para>這是玩撲克牌的排序方法。</para> 68 /// <para>一張一張地拿牌,拿到一張新牌時,就跟之前手里的牌從右到左地比較。</para> 69 /// <para>若新牌大,則將此處的舊牌向右移動,原位置空了出來。</para> 70 /// <para>當新牌不再大時,插入空位。</para> 71 /// <para>當全部牌拿完,順序就排好了。</para> 72 /// </summary> 73 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 74 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 75 public static void InsertionSort<T>(this IList<T> arr) 76 where T : IComparable 77 { 78 arr.InsertionSortDescending(); 79 } 80 /// <summary> 81 /// 插入排序 82 /// 請勿傳null給本函數,否則將發生異常 83 /// <para>穩定排序</para> 84 /// <para>插入排序(降序)原理:</para> 85 /// <para>這是玩撲克牌的排序方法。</para> 86 /// <para>一張一張地拿牌,拿到一張新牌時,就跟之前手里的牌從右到左地比較。</para> 87 /// <para>若新牌大,則將此處的舊牌向右移動,原位置空了出來。</para> 88 /// <para>當新牌不再大時,插入空位。</para> 89 /// <para>當全部牌拿完,順序就排好了。</para> 90 /// </summary> 91 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 92 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 93 /// <param name="descending">true為降序排序,false為升序排序</param> 94 public static void InsertionSort<T>(this IList<T> arr, bool descending) 95 where T : IComparable 96 { 97 if (descending) 98 arr.InsertionSortDescending(); 99 else 100 arr.InsertionSortAscending(); 101 } 102 } 103 /// <summary> 104 /// 歸並排序算法 105 /// <para>穩定排序</para> 106 /// </summary> 107 public static partial class _MergeSort 108 { 109 /// <summary> 110 /// 歸並排序(降序) 111 /// 請勿傳null給本函數,否則將發生異常 112 /// <para>穩定排序</para> 113 /// <para>歸並排序(降序)原理:</para> 114 /// <para>利用了遞歸進行排序的方法。</para> 115 /// <para>將數列等分為左右兩部分,先分別對其排序,再將分別排好的兩個數列歸並為一個排好的序列。</para> 116 /// <para>循環之,直到這部分只有1個數,那么這部分已經排好序了。</para> 117 /// <para>歸並過程,將排好的兩部分列隊,從第一個數開始比較,將較大的放到最終要排的數列。</para> 118 /// <para>若最后剩下一些數,直接接到數列最后即可。</para> 119 /// </summary> 120 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 121 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 122 public static void MergeSort<T>(this IList<T> arr) 123 where T : IComparable 124 { 125 arr.MergeSortDescending(); 126 } 127 /// <summary> 128 /// 歸並排序 129 /// 請勿傳null給本函數,否則將發生異常 130 /// <para>穩定排序</para> 131 /// <para>歸並排序(降序)原理:</para> 132 /// <para>利用了遞歸進行排序的方法。</para> 133 /// <para>將數列等分為左右兩部分,先分別對其排序,再將分別排好的兩個數列歸並為一個排好的序列。</para> 134 /// <para>循環之,直到這部分只有1個數,那么這部分已經排好序了。</para> 135 /// <para>歸並過程,將排好的兩部分列隊,從第一個數開始比較,將較大的放到最終要排的數列。</para> 136 /// <para>若最后剩下一些數,直接接到數列最后即可。</para> 137 /// </summary> 138 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 139 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 140 /// <param name="descending">true為降序排序,false為升序排序</param> 141 public static void MergeSort<T>(this IList<T> arr, bool descending) 142 where T : IComparable 143 { 144 if (descending) 145 arr.MergeSortDescending(); 146 else 147 arr.MergeSortAscending(); 148 } 149 } 150 /// <summary> 151 /// 快速排序算法 152 /// <para>不穩定排序</para> 153 /// </summary> 154 public static partial class _QuickSort 155 { 156 /// <summary> 157 /// 快速排序(降序) 158 /// 請勿傳null給本函數,否則將發生異常 159 /// <para>不穩定排序</para> 160 /// </summary> 161 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 162 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 163 public static void QuickSort<T>(this IList<T> arr) 164 where T : IComparable 165 { 166 arr.QuickSortDescending(); 167 } 168 /// <summary> 169 /// 快速排序 170 /// 請勿傳null給本函數,否則將發生異常 171 /// <para>不穩定排序</para> 172 /// </summary> 173 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 174 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 175 /// <param name="descending">true為降序排序,false為升序排序</param> 176 public static void QuickSort<T>(this IList<T> arr, bool descending) 177 where T : IComparable 178 { 179 if (descending) 180 arr.QuickSortDescending(); 181 else 182 arr.QuickSortAscending(); 183 } 184 } 185 /// <summary> 186 /// 選擇排序算法 187 /// <para>不穩定排序</para> 188 /// </summary> 189 public static partial class _SelectionSort 190 { 191 /// <summary> 192 /// 選擇排序(降序) 193 /// 請勿傳null給本函數,否則將發生異常 194 /// <para>不穩定排序</para> 195 /// </summary> 196 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 197 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 198 public static void SelectionSort<T>(this IList<T> arr) 199 where T : IComparable 200 { 201 arr.SelectionSortDescending(); 202 } 203 /// <summary> 204 /// 選擇排序 205 /// 請勿傳null給本函數,否則將發生異常 206 /// <para>不穩定排序</para> 207 /// </summary> 208 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 209 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 210 /// <param name="descending">true為降序排序,false為升序排序</param> 211 public static void SelectionSort<T>(this IList<T> arr, bool descending) 212 where T : IComparable 213 { 214 if (descending) 215 arr.SelectionSortDescending(); 216 else 217 arr.SelectionSortAscending(); 218 } 219 } 220 /// <summary> 221 /// 希爾排序算法 222 /// <para>不穩定排序</para> 223 /// </summary> 224 public static partial class _ShellSort 225 { 226 /// <summary> 227 /// 希爾排序(降序) 228 /// 請勿傳null給本函數,否則將發生異常 229 /// <para>不穩定排序</para> 230 /// </summary> 231 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 232 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 233 public static void ShellSort<T>(this IList<T> arr) 234 where T : IComparable 235 { 236 arr.ShellSortDescending(); 237 } 238 /// <summary> 239 /// 希爾排序 240 /// 請勿傳null給本函數,否則將發生異常 241 /// <para>不穩定排序</para> 242 /// </summary> 243 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 244 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 245 /// <param name="descending">true為降序排序,false為升序排序</param> 246 public static void ShellSort<T>(this IList<T> arr, bool descending) 247 where T : IComparable 248 { 249 if (descending) 250 arr.ShellSortDescending(); 251 else 252 arr.ShellSortAscending(); 253 } 254 } 255 /// <summary> 256 /// 堆排序算法 257 /// <para>不穩定排序</para> 258 /// </summary> 259 public static partial class _HeapSort 260 { 261 /// <summary> 262 /// 堆排序(降序) 263 /// 請勿傳null給本函數,否則將發生異常 264 /// <para>不穩定排序</para> 265 /// </summary> 266 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 267 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 268 public static void HeapSort<T>(this IList<T> arr) 269 where T : IComparable 270 { 271 arr.HeapSortDescending(); 272 } 273 /// <summary> 274 /// 堆排序 275 /// 請勿傳null給本函數,否則將發生異常 276 /// <para>不穩定排序</para> 277 /// </summary> 278 /// <typeparam name="T">實現了IComparable的類型<para>例如int</para></typeparam> 279 /// <param name="arr">請勿傳null給本參數,否則將發生異常</param> 280 /// <param name="descending">true為降序排序,false為升序排序</param> 281 public static void HeapSort<T>(this IList<T> arr, bool descending) 282 where T : IComparable 283 { 284 if (descending) 285 arr.HeapSortDescending(); 286 else 287 arr.HeapSortAscending(); 288 } 289 } 290 }
介紹完畢,上源碼:
http://files.cnblogs.com/bitzhuwei/SmileWei.Sorting.rar
您可以在GitHub上下載最新的源碼(https://github.com/bitzhuwei/SortingExtension)