• 常见排序算法的C#实现


    排序算法常见的有直接排序、冒泡排序、快速排序、基数排序、归并排序等,下面是实现的代码,仅供参考。

     #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();
            }
    输出结果如下图

    转载请注明出处


  • 相关阅读:
    使用Property+使用构造+构建自定义类+使用List<自定义类>(项目)
    几乎全面的食品英文总结
    网络资源深入剖析Binding(学习)
    WPF入门知识(学习)
    Get children gameobjects array and assign the script inside
    Unity3D + C#: Cloning the Content of a Serializable Class
    Use Web Fonts and the @fontface CSS Method
    Good XAML Patterns
    Coroutines & Yield
    How to make a mini map for your scene in Unity3d
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7604908.html
Copyright © 2020-2023  润新知