QuickSort 快速排序

     快速排序是一种优雅的算法,作者C.A.R.Hoare曾说,当它最初开发出Quicksort时,他认为这种算法太简单了,不值得发表,而且直到能够分析这种算法的预期运算时间之后,他才写出经典的“Quicksort”论文。

     在最坏情况下,Quicksort可能需要 n^2 的时间来对数组元素进行排序。而在最优的情况下,它将选择中值作为划分元素,因此只需 nlgn 次的比较就可以完成数组的配需。

   快速排序的基本思想是基于分治策略的。要研究这种算法,那么必须说到冒泡法排序,因为快速排序是对冒泡排序的一宗改进。它的基本思想是,通过一趟排序将戴记录分割成独立的两个部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行配需,以达到整个序列有序。

     作为一种分治策略包括三个步骤:分解-递归求解-合并;它包括三个核心部分:比较-置换-递归 。

     好,我们直接看伪代码:

 

 1//一次快速排序
 2int Partition(SqList &L,int low,int high){
 3    //交换顺序表L.r[low..high]的记录,使枢轴记录到位,并返回其所在位置,此时
 4    //在它之前(后)的记录均不大(小)与它的。
 5    L.r[0= L.r[low];
 6    pivotkey = L.r[low].key;        //用子表的第一个记录做枢轴记录
 7    while( low < high ){         //从表的两端交替的向中间扫描
 8        while( low < hith && L.r[high].key >= pivotkey )   
 9            -- high;
10        L.r[low] = L.r[high];     //将此枢轴记录小的记录交换到低端
11        while(low <high && L.r[low].key <= pivotkey)
12            ++ low;
13        L.r[low] = L.r[high];     //将比枢轴记录打的记录交换到高端
14    }

15    L.r[low] = L.r[0];
16    return low;    //返回枢轴所在位置
17}

18
19
20//递归形式的快速排序
21void QSort(SqList &L,int low , int high){
22    //对顺序表L的子序列L.r[lowhigh]做快速排序
23    if( low < high){
24        pivotloc = Partition(L, low, high);
25        QSort(L, low, pivotloc -1 );
26        QSort(L,pivotloc + 1,high);
27    }
//
28}

 

在这里,我给出一个 C# 的实现,而非 C 语言实现 (如果有必要的话我想是应该列出来的,不过这可能大多数人并不敢兴趣,或者并不是主要关注的)。

 

 1/// <summary>
 2        /// 指定数组起始和结束位置,对数组进行快速排序
 3        /// </summary>
 4        /// <param name="startIndex">数组起始下标</param>
 5        /// <param name="endIndex">数组结束下标</param>
 6        /// <param name="x">排序数组</param>

 7        public static void QuickSort(int startIndex, int endIndex, int[] x)
 8        {
 9            int i, m;
10            if (startIndex >= endIndex) return;
11            Swap(startIndex, RandomUtil.NextInt(startIndex, endIndex), x);
12            m = startIndex;
13            for (i = startIndex + 1; i <= endIndex; i++)
14            {
15                if (xIdea < x[startIndex])
16                {
17                    Swap(++m, i, x);
18                }

19            }

20            Swap(startIndex, m, x);
21            QuickSort(startIndex, m - 1, x);
22            QuickSort(m + 1, endIndex, x);
23        }

24
25        /// <summary>
26        /// 交换数组两个元素
27        /// </summary>
28        /// <param name="a">数字A</param>
29        /// <param name="b">数字B</param>

30        private static void Swap(int a, int b, params int[] x)
31        {
32            int temp = xAngel;
33            xAngel = xBeer;
34            xBeer = temp;
35        }

36

在C#中如果要对一个数组进行排序,一般就是调用 Sort(T[] array)方法,这个方法首先判断参数array是否为空,如果是则抛出System.ArgumentNullException 异常,否则它将调用 Sort(T[] array, int index, int length, IComparer comparer)方法对 array 进行排序,这个方法最后会调用 System 命名空间中的一个名为 ArraySortHelper 的类中的一个名为QuickSort(T[] keys, TValue[] values, int left, int right, IComparer comparer) 的方法,很明显这个就是排序中的核心算法了,这就是一个快速排序法,微软对这个方法进行了优化以及扩展,这种做法让排序非常的灵活。
         下面,我们一步一步的扒开整一个过程。
          那么我们就从一个假设开始吧。假如我定义了如下一个数组 object[] objects = {'a',123,1,"Test"}; 然后调用 Array.Sort(objects) 对它进行排序,微软对这个方法的描述是:
       //
        // 摘要:
        //     使用 System.Array 的每个元素的 System.IComparable 泛型接口实现,对整个 System.Array 中的元素进行排序。
        //
        // 参数:
        //   array:
        //     要排序的从零开始的一维 System.Array。
        //
        // 异常:
        //   System.ArgumentNullException:
        //     array 为 null。
        //
        //   System.InvalidOperationException:
        //     array 中的一个或多个元素未实现 System.IComparable 泛型接口。

   简而言之,就是使用比较两个对象而实现的方法对数组进行排序。那么这个方法是做什么的呢?在描述中我们还可以看到一个 System.ArgumentNullException异常,这个异常就是前面我们所说的这个方法首先判断参数array是否为空,然后抛出这个异常的,最后它将返回 Array. Sort(T[] array, int index, int length, IComparer comparer); 实现排序,这个方法的描述是:

        //
        // 摘要:
        //     使用 System.Array 的每个元素的 System.IComparable 泛型接口实现,对 System.Array 中某个元素范围内的元素进行排序。
        //
        // 参数:
        //   array:
        //     要排序的从零开始的一维 System.Array。
        //
        //   length:
        //     排序范围内的元素数。
        //
        //   index:
        //     排序范围的起始索引。
        //
        // 异常:
        //   System.ArgumentException:
        //     index 和 length 不指定 array 中的有效范围。
        //
        //   System.ArgumentNullException:
        //     array 为 null。
        //
        //   System.ArgumentOutOfRangeException:
        //     index 小于 array 的下限。- 或 -length 小于零。
        //
        //   System.InvalidOperationException:
   //     array 中的一个或多个元素未实现 System.IComparable 泛型接口。


    这个方法是 Array.Sort 系列重载的终止。(注:包括Sort(T[] array);         Sort(T[] array, IComparer comparer); Sort(T[] array, Comparison comparison); Sort(T[] array, int index, int length);)
这个方法实质也做的是对参数做一系列的判断然后抛出异常,最后如果参数都没有问题的话,它就调用 System. ArraySortHelper(这个类包括了两个重要的算法,一个是我们现在讲的快速排序,另外一个是什么呢?下篇文章我将会讲到,值得期待的。)的 Sort(array, index, length, comparer);方法。当然在调用 ArraySortHelper 中使用了不小的技巧对性能是做到至极的,好抛开这些 这个 Sort 方法又是干什么的呢?哈哈,不要以为它会感谢什么了不起的事情,它起始就调用ArraySortHelper中的  Sort(T[] keys, TValue[] values, int index, int length, IComparer comparer);方法而已。它是这样调用的:
this.Sort(items, null, index, length, comparer);
    原来是对object 类型排序了。你可能会认为,这个方法要做的就是对数组排序了吧,那就错了。它要做的是对comparer参数进行一下判断以及设定,然后调用:QuickSort(T[] keys, TValue[] values, int left, int right, IComparer comparer); 这个才是排序的核心算法。
    废话少说,马上看它的实现。

 

  1 /// <summary>
  2        /// 指定左偏移,右偏移和比较器接口使用快速排序法对T[]进行排序
  3        /// </summary>
  4        /// <typeparam name="TValue">值类型</typeparam>
  5        /// <param name="keys">关键字数组</param>
  6        /// <param name="values">值数组</param>
  7        /// <param name="left">左偏移</param>
  8        /// <param name="right">右偏移</param>
  9        /// <param name="comparer">比较器接口</param>

 10        private void QuickSort<TValue>(T[] keys, TValue[] values, int left, int right, IComparer<T> comparer)
 11        {
 12            // keys 和 values 是哈希表时候用
 13            do
 14            {
 15                int a = left;
 16                int b = right;
 17                // num3起始可以看做是一个随机数,也是特意安排的,它是取 left 到 right 的中间值
 18                //因为如果待排序数组本来就是有序的,那么就能只需递归一次
 19                int num3 = a + ((b - a) >> 1);
 20
 21                //交换keys起始位置元素和中间元素, ex: {5,3,6,7,9} -> {6,3,5,7,9}
 22                this.SwapIfGreaterWithItems<TValue>(keys, values, comparer, a, num3);
 23                //交换keys中间元素和最后元素 {6,3,5,7,9} -> {9,3,5,7,6}
 24                this.SwapIfGreaterWithItems<TValue>(keys, values, comparer, a, b);
 25                //交换keys中间元素和最后元素 {9,3,5,7,6} ->{9,3,6,7,5}
 26                this.SwapIfGreaterWithItems<TValue>(keys, values, comparer, num3, b);
 27                //  不要小看上面那三个交换,这是内有玄机的。
 28
 29                //分界点
 30                T y = keys[num3];
 31                do
 32                {
 33                    try
 34                    {
 35                        while (comparer.Compare(keysAngel, y) < 0)
 36                        {
 37                            a++;
 38                        }

 39                        while (comparer.Compare(y, keysBeer) < 0)
 40                        {
 41                            b--;
 42                        }

 43                    }

 44                    //数组越界异常
 45                    catch (IndexOutOfRangeException)
 46                    {
 47                        //throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[] { y, y.GetType().Name, comparer }));
 48                    }

 49                    //其他异常
 50                    catch (Exception exception)
 51                    {
 52                        //throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), exception);
 53                    }

 54                    if (a > b)
 55                    {
 56                        break;
 57                    }

 58                    if (a < b)
 59                    {
 60                        T local2 = keysAngel;
 61                        keysAngel = keysBeer;
 62                        keysBeer = local2;
 63                        if (values != null)
 64                        {
 65                            TValue local3 = valuesAngel;
 66                            valuesAngel = valuesBeer;
 67                            valuesBeer = local3;
 68                        }

 69                    }

 70                    a++;
 71                    b--;
 72                }

 73                while (a <= b);
 74                if ((b - left) <= (right - a))
 75                {
 76                    if (left < b)
 77                    {
 78                        this.QuickSort<TValue>(keys, values, left, b, comparer);
 79                    }

 80                    left = a;
 81                }

 82                else
 83                {
 84                    if (a < right)
 85                    {
 86                        this.QuickSort<TValue>(keys, values, a, right, comparer);
 87                    }

 88                    right = b;
 89                }

 90            }

 91            while (left < right);
 92        }

 93
 94
 95        /// <summary>
 96        /// 交换keys和values数组中的两个元素
 97        /// </summary>
 98        /// <typeparam name="TValue">值数组</typeparam>
 99        /// <param name="keys">关键字数组</param>
100        /// <param name="values">排序数组</param>
101        /// <param name="comparer">比较器接口</param>
102        /// <param name="a">数组下标A</param>
103        /// <param name="b">数组下标B</param>

104        private void SwapIfGreaterWithItems<TValue>(T[] keys, TValue[] values, IComparer<T> comparer, int a, int b)
105        {
106            if (a != b)
107            {
108                try
109                {
110                    //如果 keysAngel大于keysBeer则调换
111                    if (comparer.Compare(keysAngel, keysBeer) > 0)
112                    {
113                        T local = keysAngel;
114                        keysAngel = keysBeer;
115                        keysBeer = local;
116                        if (values != null)
117                        {
118                            TValue local2 = valuesAngel;
119                            valuesAngel = valuesBeer;
120                            valuesBeer = local2;
121                        }

122                    }

123                }

124                //数组越界异常
125                catch (IndexOutOfRangeException)
126                {
127                    //throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", new object[] { keysBeer, keysBeer.GetType().Name, comparer }));
128                }

129                //其他异常
130                catch (Exception exception)
131                {
132                    //throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), exception);
133                }

134            }

135        }

136

其核心算法和基本的快速排序是有所改变的。

欢迎大家指点批评! 

posted on 2009-11-26 09:01  Jetson Lee  阅读(576)  评论(0编辑  收藏  举报

中山房地产信息网    中山楼盘   中山二手房