• 关于快速排序算法(一个90%的人都不懂其原理、99.9%的人都不能正常写出来的算法.)


    一、奇怪的现象

      研究快速排序很久了,发现一个古怪的实情:这算法描述起来很简单,写一个正确的出来实在不容易.写一个优秀的快速排序算法更是难上加难.

    也难怪该算法提出来过了很久才有人写出一个正确的算法,过了很久才优秀的版本出来.

    二、原理描述

    1. 从数列中挑出一个元素,称为 "基准"(pivot),
    2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
    3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序.

    三、最容易让人理解的版本

    一个List形式的数组,找到其中的第一个做基准,遍历剩下的数据,然后创建两个左右List,大的放右边,小的放左边.然后对左右List各自进行如上操作.......

    详情见代码

    ​using  System;
    using  System.Collections.Generic;
    
    using  System.Text;
    namespace test
    {
        class Program
        {
            static void Main(string[]args)
            {
                List<int> array=new List<int>();
                array.AddRange(new int[]{3,2,9,5,8,6,23,23,222,12,21});
                var t1=DateTime.Now.Ticks;
                sort(array);
                var t2=DateTime.Now.Ticks;
                Console.WriteLine(t2-t1);
                
                Console.ReadLine();
            }
            static int Count=0;
            public static void sort(List<int> array)
            {
                var guid=Count++;
                Console.WriteLine();
                Console.Write("目标字符串:("+guid+")");
                Show(array);
                
                if (array.Count<=1) {
                    return;
                }
                if (array.Count==2) {
                    if (array[0]>array[1]) {
                        var temp=array[0];
                        array[0]=array[1];
                        array[1]=temp;
                        Console.Write("双值交换:");
                        Show(array);
                    }
                }
                else{
                    var xData=array[0];
                    var leftList=new List<int>();
                    var rightList=new List<int>();
                    for (int i = 1; i < array.Count; i++) {
                        var t=array[i];
                        if (t<=xData) {
                            leftList.Add(t);
                        }else{
                            rightList.Add(t);
                        }
                    }
                    
                    Console.WriteLine("中间值:"+xData);
                    
                    Console.Write("左边的字符串("+guid+"):");
                    Show(leftList);
                    
                    Console.Write("右边的字符串("+guid+"):");
                    Show(rightList);
                    
                    sort(leftList);
                    Console.Write("左边的字符串(排序后)("+guid+"):");
                    Show(leftList);
                    
                    sort(rightList);
                    Console.Write("右边的字符串(排序后)("+guid+"):");
                    Show(rightList);
                    
                    array.Clear();
                    array.AddRange(leftList);
                    array.Add(xData);
                    array.AddRange(rightList);
                    Console.Write("排好的("+guid+"):");
                    Show(array);
                    
                    Console.WriteLine();
                    leftList.Clear();
                    rightList.Clear();
                }
            }
            public static void Show(List<int>array){
                foreach (var a in array) {
                    Console.Write(a+",");
                }
                
                Console.WriteLine();
            }
        }
    }
    

     四、正确但不优化的版本

    using System;
    namespace Sort
    {
        class Program
        {
            static void Main(string[] args)
            {
                string result = string.Empty;
                int[] unsort = {  2, 0, 3, 7, 5,6 };
                //快速排序
                QuickSort(unsort, 0, unsort.Length - 1);
                Console.ReadLine();
            }
    
            /// <summary>
            /// 调用快速排序算法
            /// </summary>
            /// <param name="unsort">待排序的整形数组</param>
            /// <param name="left">左边起始点</param>
            /// <param name="right">右边结束点</param>
            public static void QuickSort(int[] unsort, int left, int right)
            {
                if (left < right)
                {
                    //获取一次排序的中间索引位置
                    int midPosition = GetSplitNum(unsort, left, right);
                    
                    //递归实现
                    QuickSort(unsort, left, midPosition - 1);
                    QuickSort(unsort, midPosition + 1, right);
                }
            }
             
            static int ORDER_INDEX=1;
            /// <summary>
            /// 获取一次排序的中间索引位置
            /// </summary>
            /// <param name="unsort">待排序的整形数组</param>
            /// <param name="left">左边起始点</param>
            /// <param name="right">右边结束点</param>
            public static int GetSplitNum(int[] unsort, int left, int right)
            {
                int splitNum = unsort[left];
                while (left < right)
                {
                    /**
                     * 从右端开始比较
                     * (1)假如从右端过来的数比分隔数要大,则不用处理
                     * (2)假如从右端过来的数比分隔数要小,则需要挪到分隔线左边
                     * */
                    while (left < right && splitNum <= unsort[right])
                    {
                        right--;
                    }
                    unsort[left] = unsort[right];
                    GetPrint(unsort);
                    /**
                     * 从从端开始比较
                     * (1)假如从左端过来的数比分隔数要小,则不用处理
                     * (2)假如从左端过来的数比分隔数要大,则需要挪到分隔线右边
                     * */
                    while (left < right && splitNum >= unsort[left])
                    {
                        left++;
                    }
                    unsort[right] = unsort[left];
                    GetPrint(unsort);
                }
                //一趟比较之后,分隔数的位置就可以确认起来
                unsort[left] = splitNum;
                Console.WriteLine(string.Format("第{0}轮排序完毕",(ORDER_INDEX++)));
                GetPrint(unsort);
                return left;
            }
    
            /// <summary>
            /// 打印输出结果
            /// </summary>
            /// <param name="unsort">数据</param>
            public static string GetPrint(int[] unsort)
            {
                string result = string.Empty;
                foreach (int n in unsort)
                {
                    if (!string.IsNullOrEmpty(result))
                    {
                        result += string.Format("->{0}", n);
                    }
                    else
                    {
                        result = string.Format("{0}", n);
                    }
                }
                Console.WriteLine(result);
                return result;
            }
            public static string GetPrint(int[] unsort,int replaceIndex)
            {
                string result = string.Empty;
                foreach (int n in unsort)
                {
                    if (!string.IsNullOrEmpty(result))
                    {
                        result += string.Format("->{0}", n);
                    }
                    else
                    {
                        result = string.Format("{0}", n);
                    }
                }
                Console.WriteLine(result+"   ==>"+replaceIndex);
                return result;
            }
        }
    }

     

  • 相关阅读:
    cocos2dx 2.14使用UUID
    cocos2dx游戏项目总结(持续更新)
    window mac iPhone 三种比较相似的字体
    【luogu P4762】字符串合成 / Virus synthesis(PAM)(DP)
    【luogu P7796】图书管理员 / POLICE(并查集)(树状数组)
    【luogu P5494】【模板】线段树分裂(线段树合并)(线段树分裂)
    【luogu P2595】多米诺骨牌(插头DP)(容斥)
    送分大水题(高维前缀和)(高维差分)
    【luogu P6880】Bus / 奥运公交 / オリンピックバス(最短路)
    【luogu P1879】Corn Fields G / 玉米田++ / 玉米田(加加强版)(状压DP)(轮廓线DP)
  • 原文地址:https://www.cnblogs.com/humble/p/3703757.html
Copyright © 2020-2023  润新知