排序之快速排序

快速排序之所以叫快速排序,肯定要配得上它的名字。我们就来看看它是如何这么快的。

快速排序的原理

快速排序是霍尔创建的,是通过以第一个或者最后一个数值作为比较值key,形成一个它的左边比它都小,右边比它都大的情况,然后把这个再成左右两个部分重复这个操作,一直细化。

霍尔版本

而霍尔的方法就是左右(l,r)两个指针向中间靠近,如果l遇到的值比key的值大就停住,r遇到比key小的值也停下,然后交换l,r的值,一直重复这个操作到两个指针相遇,将相遇的值与key交换就是最终要完成的情形

我们来分析一下这个过程

首先r先走找到5比6小,然后l走找到7

然后交换两者

继续这个操作,r先走,l后走找到4和9

然后交换

然后重复,r先走找到3,l后走与它相遇,相遇就停止

然后交换3和key

key就到了中间,形成我们需要到这个情况

接下来就是将这个操作分成左右两个,key左边重复操作,右边也是一样。那么这个操作会迭代出两个分支,然后一直二分下去,一直要l>=r的时候我们就停止。

我们很明显的发现可以用递归来完成这个操作。

提醒点

我一直在强调现r走再l走肯定有原因,主要是保证任何时候key和重合地方交换的时候,k都是比这个值大的。

那么我们就来证明一下:

循环结束的情况只有两种,一种是l撞到r,一种是r撞到l

第一种:因为是l撞到r,说明r已经走了,那么r停的地方一定是比key要大的,所以最后交点比

key大。

第二种:这种情况是出现在上一次,l和r交换后的,原先r的值交给了现在的l,那么现在的r重合于r就是之前r的值,之前r停止是比key大的,所以还是比key大。

综上任何情况都是比key大的。

如果我们反过来先让l走,那么不会出现上面的情况。

挖坑法

挖坑发就是先把key处的值取出来,然后就只有一个坑需要其他的值填,那么就让r向前走找到比key小的值放到坑出,那么现在r的地方又有一个坑,我们就要l向后走找比key大的值填坑。然后又是r,又是l...一直到两个相遇。最后一个坑就由key填下。

前后指针法

前后指针法相对有点抽象:

cur遇到比key小的就和++prev交换

上面是快排最基础的形式

还存在一定的缺陷,我们往下看

缺陷

上面三种都是有缺陷的

当排的是顺序数据的时候时间复杂度会坍缩成N²,并且会导致递归深度太深栈溢出。

霍尔和挖坑是差不多的,当r往前移动会在第一个相遇,然后分为左右,第二次递归的右边会在第二个下标相遇,然后第三个一直到末尾。就是N²。

前后指针法的cur会一直往后到循环结束,然后递归到下一次。也是n²的时间复杂度。

为了防着这种情况,有一个三数取中的算法让l,mid,r中第二大的数搞到最开始,这样可以尽可能的保证一趟排序完后key左右两边的长度大概相同。

然后我们将之前的三段代码写成单趟的:

那么可以变成这样写 

优化

我们看到递归是二分的,那么就像二叉树一样。那么最后一层递归量相当于前面的一半,而且最后一层也没有多大长度。我们就可以用其他的排序来解决:

防栈溢出

用递归还是有栈溢出的风险,所以我们安排非递归:

用栈也是可以的,模仿递归。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值