Introduction to Algorithm(chapter 7)

快速排序,快排思想上类似于归并排序,都是采用分治法的思想,归并排序是将一列数分成两半,然后单独对两半处理,最后再合并;而快排也是将一列数据分成两列,分别对两列进行处理,最后再合并,但这里的合并是不需要做任何操作的。

对于一组数A[p.....r],快排是在p...r中找到q,使得A[p...q-1] <= A[q] <= A[q+1....r],也就是使这组数分为两小组,左边的数都小于pivot,右边的数都大于pivot,然后再分别对左右两小组数进行类似的处理直至最后完成排序。这里的关键在于如何寻找q使得它满足这个性质,寻找q的过程即快排中的关键步骤partition(),这里主要采用的方法是选定最后一个元素为pivot,然后从头开始遍历保持一个遍历游标,同时保持另一个游标使得此游标之前的数都小于pivot,这样一趟遍历完即完成分割找到q。随机化快排的平均时间为o(n*lgn),如果每次的分割都是最不平均的分割那么导致快排的最坏时间为o(n^2)。要注意快排这样一个从大数组到小数组的过程,即从上到下的过程,而归并排序在从上到下后有一个从下到上的合并过程,因为快排是原地排序故不需要这样的从下到上的过程而完成排序。

快速排序其实是产生一个二叉排序树,根节点为A[q],左孩子为A[p...q-1],右孩子为A[q+1...r],通过这颗二叉排序树来完成排序,最坏的情况就对应着这棵树是极不平衡的情况,即o(n^2)

快排的绝妙的地方也正在于此,即分割方法产生的二叉排序树的应用。至于分割方法,有两种典型实现,原始的hoare分割方法,是两个游标从左右两头向中间靠近,然后不断交换或者补充空的位置,而更易理解的方法是从一边向另一边遍历,例如从左向右遍历利用游标j,同时维护一个游标i使所有i左边的元素都比A[i]要小,然后在j向右遍历的过程中如果遇到A[j] > pivot的情况那么交换A[j],A[i],然后i++,这样分割方法导致每个比pivot小的元素都要交换一次,而hoare仅仅进行必要的交换,即交换的次数减少了,不过两种分割方法的时间都为o(n),影响的只是常数因子。


当将一数组划分成两部分后,可以先对元素个数少的那部分进行先递归调用然后再调用元素多的那部分,这样可以减少栈的深度即减少栈的使用空间

快排的第二个优化在于Pivot的选择,往往三数取中效果要比选取头或者尾要好

快排的第三个优化在于当数组中元素较少时直接返回 ,这样整个数组成了一段一段有序的了 再利用插入排序一次即可完成,这样提高效率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值