最常见的几种排序算法原理和C#实现类库
本文尽量用简单直白通俗易懂深入浅出详实通透的手法将常见的几种排序算法的原理和代码呈现给众位,欢迎批评指教!
为简单起见,本文所述排序默认都以升序排序为例。(当然最后给出的源代码是升序降序都有的)
冒泡排序(Bubble sort)
冒泡排序每轮都得到数列中的最大值,同时将其置于最后,然后对剩余部分进行排序。
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)
堆排序总是建立这样一个二叉树:其父结点总大于其子结点。
首先建堆。
每轮将根结点与最后一个结点互换,然后对剩余部分建堆。
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)
每轮将数列未排序部分的第一个数字插入已排好的部分。
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)
递归方法。将数列均分为前后两部分,分别对其进行归并排序,然后将分别完成排序的前后两部分归并。
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)
选择一个数(比如第一个),依次右、左、右、左地将它右侧比它小的与之互换,将它左侧比它大的与之互换,最后这个数就排好了。
分别对这个数左右两部分进行快速排序。
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)
每轮找到最小的数,与未排序部分的第一个互换。
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设置一系列增量,将序号之差等于增量的数字进行之间插入排序。
Shell sort
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 ...;"之类的东西,只需引用此类库就行了。
namespace System下的扩展排序算法
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 }
介绍完毕,上源码:
https://files.cnblogs.com/bitzhuwei/SmileWei.Sorting.rar
您可以在GitHub上下载最新的源码(https://github.com/bitzhuwei/SortingExtension)
微信扫码,自愿捐赠。天涯同道,共谱新篇。
微信捐赠不显示捐赠者个人信息,如需要,请注明联系方式。 |