快速排序优化分析

来源:互联网 发布:js点击弹出 编辑:程序博客网 时间:2024/05/11 05:30

上一篇的《浅谈快速排序》 http://blog.csdn.net/g96968586/article/details/24185967  

中我们分析了快速排序的算法,我们也举了一个例子来模拟快速排序,然而大家发现了没有,上次是对数组{50,10,90,30,70,40,80,60,20}进行排序,如果这一次我换成下面这个例子会发生什么情况呢?

前一篇的Partition函数代码:
int Partition ( SqList *L,int low,int high){       int pivotkey;       pivotkey = L->r[low];   /* 用子表的第一个记录作枢轴记录 */       while(low < high)   /* 从表的两端交替向中间扫描 */       {            while(low < high && L->r[high] >= pivotkey)    high - - ;            swap(L,low,high);    /* 将比枢轴记录小的记录交换到低端 */            while(low < high && L->r[low] <= pivotkey )   low ++;            swap(L,low,high);  /* 将比枢轴记录大的记录交换到高端 */        }          return low;   /*  返回枢轴所在位置 */}


如果我们对数组{9,1,5,8,3,7,4,6,2}进行排序,由代码第四行“pivotkey = L->r[low]; ”知道,我们应该选取9作为第一个枢轴pivotkey,此时经过一轮“pivot=Partition(L,1,9)”,它只是更换了9和2的位置,并把9返回给pivot。整个数组并没有实质性的变化。如图示,


换句话说,第四行代码“pivotkey = L->r[low]; ”变成了一个潜在的瓶颈。排序速度的快慢取决于L->r[l1]的关键字处在整个序列的位置,L->r[1]太大或太小都回影响性能。在我们现实中,带排序的序列极有可能是基本有序的,如果我们总是固定地选择第一个关键字作为首个枢轴,就变成了极为不合理的做法。
这里的改进方法我们采用三数取中法。即取三个关键字先进行排序,将中间数作为枢轴,一般是取整个待排序的左端、右端和中间三个数,也可以随机选取。这样至少这个中间数一定不会是最小或者是最大的数,从概率来说,取三个数均为最小或最大的可能性微乎其微,因此中间数位于较为中间的值的可能性就大大提高了。

我们现在在Partition函数的第三行和第四行中间加入这么一段代码,


这样子,如果我们对数组{9,1,5,8,3,7,4,6,2},取左9、中间3、右2来比较,最终使得L->r[low] = 3,一定要比9和2来的更合理。


下面来优化一些不必要的交换。
大家发现了没,上一篇中,对于50这个关键字,其位置变化是1->9->3->6->5,可其实它的最终目标就是5,当中的一些交换是不需要的。因此,我们再次对Partition函数进行优化。


优化之后少了多次交换数据的操作,在性能上又得到了部分的提高。

看程序分析,



今天就到这吧o(∩_∩)o,顺便吐槽一下,CSDN怎么认为我的代码有敏感词汇,总是不让我保存和发布,最后我只能在自己电脑上敲入代码,截图发布上来了,如果谁在我的代码上看到了敏感词汇,请告诉我,谢谢!


0 0