排序算法常见的有直接排序、冒泡排序、快速排序、基数排序、归并排序等,下面是实现的代码,仅供参考。
#region DirectSort /// <summary> /// 直接排序. /// 第一次从R[0]~R[n-1]中选取最小值,与R[0]交换, /// 第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,...., /// 第i次从R[i-1]~R[n-1]中选取最小值,与R[i-1]交换,....., /// 第n-1次从R[n-2]~R[n-1]中选取最小值,与R[n-2]交换, /// 总共通过n-1次,得到一个按排序码从小到大排列的有序序列· /// </summary> /// <param name="data"></param> /// <returns></returns> private static int DirectSort(int[] data) { int min = 0; int k = 0; int count = 0; for (int i = 0; i < data.Length; i++) { min = data[i]; k = i; for (int j = i; j < data.Length; j++) { if (min > data[j]) { min = data[j]; k = j; } count++; } data[k] = data[i]; data[i] = min; } return count; } #endregion #region BubbleSort /// <summary> /// 冒泡排序. /// 重复地走访过要排序的数列,一次比较两个元素, /// 如果他们的顺序错误就把他们交换过来。 /// 走访数列的工作是重复地进行直到没有再需要交换, /// 也就是说该数列已经排序完成。 /// 这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。 /// </summary> /// <param name="data"></param> private static int BubbleSort(int[] data) { int min = 0; int count = 0; for (int i = 0; i < data.Length; i++) { for (int j = 0; j < data.Length - 1 - i; j++) { if (data[j] > data[j + 1]) { min = data[j + 1]; data[j + 1] = data[j]; data[j] = min; } count++; } } return count; } #endregion #region QuickSort /// <summary> /// 快速排序. /// 通过一趟排序将要排序的数据分割成独立的两部分, /// 其中一部分的所有数据都比另外一部分的所有数据都要小, /// 然后再按此方法对这两部分数据分别进行快速排序, /// 整个排序过程可以递归进行,以此达到整个数据变成有序序列。 /// </summary> /// <param name="data"></param> /// <returns></returns> private static int QuickSort(int[] data) { int count = 0; QuickSortInner(data, 0, data.Length - 1, ref count); return count; } private static void QuickSortInner(int[] data, int left, int right, ref int count) { if (left >= right) { return; } //完成一次单元排序 int middle = QuickSortUnit(data, left, right, ref count); //对左边单元进行排序 QuickSortInner(data, left, middle - 1, ref count); //对右边单元进行排序 QuickSortInner(data, middle + 1, right, ref count); } private static int QuickSortUnit(int[] data, int left, int right, ref int count) { int key = data[left]; while (left < right) { //自右端向左端查找小于key的值 for (; ; right--) { if (data[right] < key || right <= left) {//右边有小于key的值,直接将该值放到左边, //此时right位置的空间空出,留作放置从左边比较出的大于key的值。 //如果右索引已经到达了左边,right==left,data[left] = data[right]是同数据交换,不受影响. data[left] = data[right]; count++; break; } } //自左端向右端查找大于key的值 for (; ; left++) { if (data[left] > key || left >= right) {//左边有大于key的值,直接将该值放到右边, //此时left位置的空间空出,留作放置从右边比较出的小于key的值,或者用来最后放置key. //如果左索引已经到达了右边,left==right,data[right] = data[left]是同数据交换,不受影响. data[right] = data[left]; count++; break; } } } data[left] = key; return right; } #endregion #region RadixSort /// <summary> /// 基数排序(此处采用LSD法). /// 属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort, /// 顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用, /// 基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数, /// 在某些时候,基数排序法的效率高于其它的稳定性排序法。 /// ==基数排序又分MSD和LSD。 /// ==最高位优先(Most Significant Digit first)法,简称MSD法: /// 先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组, /// 之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。 /// 再将各组连接起来,便得到一个有序序列。 /// ==最低位优先(Least Significant Digit first)法,简称LSD法: /// 先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。 /// </summary> /// <param name="data"></param> /// <returns></returns> private static int RadixSort(int[] data) { var bucketList = new List<List<int>>(); for (int i = 0; i < 10; i++) { bucketList.Add(new List<int>()); } int count = 0; int positionValue = 0; int maxPosition = 1; //计算最大位数 for (int i = 0; i < data.Length; i++) { var str = data[i].ToString(); if (str.Length > maxPosition) { maxPosition = str.Length; } } for (int position = 0; position < maxPosition; position++) { //分桶 for (int i = 0; i < data.Length; i++) { positionValue = 0; var str = data[i].ToString(); var index = (str.Length - 1) - position;// 计算出对应位数的字符串的值 if (index >= 0 && str.Length > index) { positionValue = int.Parse(str.Substring(index, 1)); } bucketList[positionValue].Add(data[i]); count++; } //合并桶 int j = 0; foreach (var bucket in bucketList) { foreach (var val in bucket) { data[j++] = val; } //清空桶 bucket.Clear(); } } return count; } #endregion #region MergeSort /// <summary> /// 归并排序. /// 该算法是建立在归并操作上的一种有效的排序算法, /// 该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 /// 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。 /// 若将两个有序表合并成一个有序表,称为二路归并。 /// ===归并过程为: /// 比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1; /// 否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完, /// 然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。 /// 归并排序的算法我们通常用递归实现,先把待排序区间[s, t]以中点二分,接着把左边子区间排序, /// 再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s, t]。 /// </summary> /// <param name="data"></param> /// <returns></returns> private static int MergeSort(int[] data) { int count = 0; MergeSortInner(data, 0, 1, ref count); return count; } /// <summary> /// 二路归并. /// 原理:将两个有序表合并成一个有序表 /// </summary> /// <param name="data"></param> /// <param name="firstStart">第一个有序表的起始下标</param> /// <param name="secondStart">第二个有序表的起始下标</param> /// <param name="secondTail">第二个有序表的结束下标</param> private static void MergeSortUnit(int[] data, int firstStart, int secondStart, int secondTail, ref int count) { int[] newArr = new int[secondTail - firstStart + 1]; int firstIndex = firstStart, secondIndex = secondStart, newIndex = 0; while (firstIndex < secondStart && secondIndex <= secondTail) {//自小而大合并到一个序列中 if (data[firstIndex] <= data[secondIndex]) { newArr[newIndex] = data[firstIndex++]; } else { newArr[newIndex] = data[secondIndex++]; } newIndex++; count++; } for (; firstIndex < secondStart; firstIndex++, newIndex++) { newArr[newIndex] = data[firstIndex]; count++; } for (; secondIndex <= secondTail; secondIndex++, newIndex++) { newArr[newIndex] = data[secondIndex]; count++; } Array.Copy(newArr, 0, data, firstStart, newArr.Length); } /// <summary> /// 归并排序 /// </summary> /// <param name="data"></param> /// <param name="firstStart">第一个序列的起始索引</param> /// <param name="len">每次归并的有序集合的长度</param> private static void MergeSortInner(int[] data, int firstStart, int len, ref int count) { int size = data.Length; //归并排序具体工作原理如下(假设序列共有n个元素): //将序列每相邻两个数字进行归并操作(merge),形成floor(n/2)个序列,排序后每个序列包含两个元素 //将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素 //将上述序列继续归并,形成floor(n/K)个序列(其中k为2的t次方),直到所有元素排序完毕。 int k = len << 1; //新标准序列的组数 int groupStandard = size / k; //除了标准序列外剩余的元素个数 int leftElement = size % k; // size & (k - 1); //归并到只剩一个有序集合的时候结束算法 if (groupStandard == 0) { return; } int secondStart = 0; int secondTail = 0; //进行一趟归并排序 for (int i = 0; i < groupStandard; i++) { firstStart = i * 2 * len; secondStart = firstStart + len; secondTail = (len << 1) + firstStart - 1; MergeSortUnit(data, firstStart, secondStart, secondTail, ref count); } //将剩下的数和倒数第一个有序集合归并 if (leftElement != 0) { firstStart = size - leftElement - 2 * len; secondStart = size - leftElement; secondTail = size - 1; MergeSortUnit(data, firstStart, secondStart, secondTail, ref count); } //递归执行下一趟归并排序 MergeSortInner(data, 0, 2 * len, ref count); } #endregion以上各排序算法的解释主要来自于百度,仅供参考。
static void Main(string[] args) { var data = new int[] { 123, 45, 21, 456, 98, 40, 32, 1435, 76, 485, 89, 876, 908, 345, 123 }; Console.WriteLine(string.Join(",", data)); //直接排序 Console.WriteLine("=======直接排序======"); var dataTemp = new int[data.Length]; data.CopyTo(dataTemp, 0); var count = DirectSort(dataTemp); Console.WriteLine(count + "次=>" + string.Join(",", dataTemp)); //冒泡排序 Console.WriteLine("=======冒泡排序======"); dataTemp = new int[data.Length]; data.CopyTo(dataTemp, 0); count = BubbleSort(dataTemp); Console.WriteLine(count + "次=>" + string.Join(",", dataTemp)); //快速排序 Console.WriteLine("=======快速排序======"); dataTemp = new int[data.Length]; data.CopyTo(dataTemp, 0); count = QuickSort(dataTemp); Console.WriteLine(count + "次=>" + string.Join(",", dataTemp)); //基数排序 Console.WriteLine("=======基数排序======"); dataTemp = new int[data.Length]; data.CopyTo(dataTemp, 0); count = RadixSort(dataTemp); Console.WriteLine(count + "次=>" + string.Join(",", dataTemp)); //归并排序 Console.WriteLine("=======归并排序======"); dataTemp = new int[data.Length]; data.CopyTo(dataTemp, 0); count = MergeSort(dataTemp); Console.WriteLine(count + "次=>" + string.Join(",", dataTemp)); Console.ReadLine(); }输出结果如下图
转载请注明出处