代码改变世界

算法学习之快速排序

2010-12-20 22:01  MichaelYin  阅读(351)  评论(0编辑  收藏  举报

快速排序通常是用于排序的最佳实用选择,因为它的平均性能相当好。

快速排序和先前讲到的合并排序一样,体现了算法设计中的分治的思想。我们首先将问题进行分解,将数组划分成两个部分A[p…q-1]和A[q+1…r],使得A[p…q-1]中的元素小于等于A[q],然后分别解决前面一个数组和后面一个数组的排序,最后进行合并,由于这两个数组是就地排序(in place)的,所以不用像合并排序中一样进行过多的合并的操作。

由于中间的分别排序的部分可以使用递归实现,所以快速排序中关键的地方就是如何将数组进行分解了。

        /// <summary>
        /// 对数组进行分组,返回分界处的index
        /// </summary>
        public static int Partition(int[] array, int firstIndex, int secIndex)
        {
            int key = array[secIndex];
            int k = firstIndex;
            for (int j = firstIndex; j < secIndex; j++)
            {
                if (array[j] < key)
                {
                    Utils.Swap(ref array[k], ref array[j]);
                    k++;
                }
            }
            //将最后一个元素和对应的分解出的元素互换
            Utils.Swap(ref  array[k], ref array[secIndex]);
            return k;
        }

 

先将最后一位的值取出来作为比较的Key,k左边全部是小于Key的值,由于开始还没有比较,所以k = firstIndex,如果发现有小于Key的值就和K指向的数进行替换,并且k值加1,最后的情况就是k左边的值就都比Key小,最后一行的Utils.Swap(ref array[k], ref array[secIndex]);将含有Key的值移到了中间,这样就实现了拆分数组并且前面小于等于A[k]的值。下面是快速排序的代码

        public static void Sort(int[] array, int firstIndex, int secIndex)
        {
            if (firstIndex < secIndex)
            {
                int index = RandomPartition(array, firstIndex, secIndex);
                //递归调用
                Sort(array, firstIndex, index - 1);
                Sort(array, index + 1, secIndex);
            }
        }
        

下面就快速排序还顺带讲一点随机化的知识,虽然我们假定输入数据的所有排列顺序都是等可能的,但是在实际工程中,这个假设不一定总是成立,所以,我们需要在算法中人为的加入随机化成分,以便对于所有输入,它能获得较好的平均情况性能

        public static int RandomPartition(int[] array, int firstIndex, int secIndex)
        {
            //从中随机选出一个index,然后和最后一个元素互换
            int j = RandomFactory.GetRandomInt(firstIndex, secIndex);
            Utils.Swap(ref array[j], ref array[secIndex]);
            return Partition(array, firstIndex, secIndex);
        }
原理其实很简单,就是在分解之前随机的从数组中选取一个数和最后一个元素互换,这样的本质就是数组中的任何一个元素都有可能作比较的那个Key。