关于快速排序算法(一个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;
        }
    }
}

 

posted @ 2014-05-02 10:38  [秦时明月]  阅读(5199)  评论(3编辑  收藏  举报