- 版本一 使用双指针交替从左(右)两边分别开始寻找大于基准值(小于基准值) , 然后与基准值交换 , 直到最后左右指针相遇 。
- 版本二 使用双指针向中间集合 , 左指针遇到大于基准值时则停止 , 等待右指针 , 右指针遇到小于基准值时则停止 , 与左指针指向的元素交换 , 最后基准值放到合适位置 。

文章插图
快速排序的递归演示
- 版本一递归代码的排序过程示意图:

文章插图
步骤1: 选择第一个元素为基准值pivot=a[left]=5,right指针指向尾部元素 , 此时先由right自右向左扫描直至遇到<5的元素 , 恰好right起步元素4<5 , 因此需要将4与5互换位置;
步骤2: 4与5互换位置之后 , 轮到left指针从左向右扫描 , 注意一下left的起步指针指向了由步骤1交换而来的4 , 新元素4不满足停止条件 , 因此left由绿色虚箭头4位置游走到元素9的位置 , 此时left找到9>5 , 因此将此时left和right指向的元素互换 , 也就是元素5和元素9互换位置;
步骤3: 互换之后right指针继续向左扫描 , 从蓝色虚箭头9位置游走到3的位置 , 此时right发现3<5 , 因此将此时left和right指向的元素互换 , 也就是元素3和元素5互换位置;
步骤4: 互换之后left指针继续向右扫描 , 从绿色虚箭头3位置游走到6的位置 , 此时left发现6>5 , 因此将此时left和right指向的元素互换 , 也就是元素6和元素5互换位置;
步骤5: 互换之后right指针继续向左扫描 , 从蓝色虚箭头6位置一直游走到与left指针相遇 , 此时二者均停留在了pivot=5的新位置上 , 且左右两边分成了两个相对于pivot值的子序列;
循环结束:至此出现了以5为基准值的左右子序列 , 接下来就是对两个子序列实施同样的递归步骤 。
以第二次和第三次左子序列递归循环为例:

文章插图
步骤1-1:选择第一个元素为基准值pivot=a[left]=4 , right指针指向尾部元素 , 此时先由right指针向左扫描 , 恰好起步元素3<4 , 因此将3和4互换;
步骤1-2:互换之后left指针从元素3开始向右扫描 , 一直游走到与right指针相遇 , 此时本次循环停止 , 特别注意这种情况下可以看到基准值4只有左子序列 , 无右子序列 , 这种情况是一种退化 , 就像冒泡排序每次循环都将基准值放置到最后 , 因此效率将退化为冒泡的O(n^2);
步骤1-3:选择第一个元素为基准值pivot=a[left]=3 , right指针指向尾部元素 , 此时先由right指针向左扫描 , 恰好起步元素1<3 , 因此将1和3互换;
步骤1-4:互换之后left指针从1开始向右扫描直到与right指针相遇 , 此时注意到pivot=3无右子序列且左子序列len=1 , 达到了递归循环的终止条件 , 此时可以认为由第一次循环产生的左子序列已经全部有序 。
循环结束:至此左子序列已经排序完成 , 接下来对右子序列实施同样的递归步骤 , 就不再演示了 , 聪明的你一定get到了 。
特别注意:
以上过程中left和right指针在某个元素相遇 , 这种情况在代码中是不会出现的 , 因为外层限制了i!=j , 图中之所以放到一起是为了直观表达终止条件 。
- 版本二C++版本动画演示:

文章插图
分析一下:
个人觉得这个版本虽然同样使用D&C思想但是更加简洁 , 从动画可以看到选择pivot=a[end] , 然后左右指针分别从index=0和index=end-1向中间靠拢 。
过程中扫描目标值并左右交换 , 再继续向中间靠拢 , 直到相遇 , 此时再根据a[left]和a[right]以及pivot的值来进行合理置换 , 最终实现基于pivot的左右子序列形式 。
推荐阅读
- 跑步能帮助我们减大腿肉吗?
- 盘你是啥意思 男生对女生说盘你是什么意思
- 迷你组合音响推荐
- 迷你插卡小音箱使用方法介绍
- 蹲马步提升你的性能力
- 跑步机上请你收腹挺胸
- 9步保健操唤醒女人身体欲望
- 金骏眉你真的了解吗? 金骏眉属于什么茶
- 开车转弯总是很飘,不稳怎么办 教你几招正确的转弯技巧
- 你家电视升级了吗?你满意吗?
