快速排序(算法A)
看完你能徒手推导轴点划分每一步,并说清最坏情形何时发生
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
快速排序(算法A)
看完你能徒手推导轴点划分每一步,并说清最坏情形何时发生
什么是分而治之
面对一大箱乱放的书,没人会一口气整理完。聪明的做法是:先分堆,各堆各自整理,最后按顺序把堆摞起来——这就是快速排序背后的分而治之思想。
分堆对应拆小,逐堆整理对应递归求解,摞堆对应合并
分治在快排中的映射
从上往下看:数组如何被轴点层层切分,最后为什么不需要合并这一步。
快排的整体思路
上一页我们把数组拆成了「轴点 + 左右两堆」。现在把分治的完整流程串起来:其实快排整件事,就浓缩成三个反复执行的动作。
抽出一本对照书、按厚薄分两边、再分别整理两小堆
什么是轴点
上一页说,快排把区间拆成两半的关键,是先找一个「基准」。想想排队时老师挑出一个人,喊一声:比你矮的站左边,比你高的站右边——这个人就是轴点。
被挑中的同学对应轴点,左右两队对应不大于与不小于它的两半
轴点的两个性质
顺着箭头看:轴点归位后,左区全部不大于它,右区全部不小于它。
轴点与有序的关系
前面我们认识了轴点的两个性质。现在追问一句:轴点离开位后,自己跑去哪了?答案是——它落在哪,哪就是它的最终位置。这一页我们把这话说清楚。
你的分数介于两边同学之间,排完无论怎么排你都在这个座位
构造轴点的思路
构造轴点分四步:先立候选,再逐个比较、各归两侧,最后落位。
swap 与移动的代码骨架
用一段真实可运行的 Python,看清比较、交换、轴点归位三件事的最小骨架。
partition 用'挖坑填坑'替代反复 swap:j 找小者填左坑,i 找大者填右坑,最后 pivot 归位,正好满足轴点的两个性质。
单调性:查找交换的节奏
上一页搭好了 swap 骨架,但还差一个关键问题:往哪儿搬?答案是两个哨兵从两头向中间扫——右边的找小的,左边的找大的,每换一次,可行区间就缩一截。
两队各自清查半条街,清一段少一段,最终碰头
不变性:为什么不会出错
沿着箭头看:每一轮交换后,左右两区的不变式依然成立,直到扫描结束轴点归位。
实例:完整走一遍
用序列 5 3 8 1 9 2 走一遍划分,轴点 5 逐步归位。
自测:轴点归位
对序列 [4,1,3,5,2] 做一轮划分(以 4 为轴点,构造完成后),轴点 4 位于哪个位置(下标从 0 起)?
要点收束
- ✓分治三问——切、治、合,快排的「合」是免费的
- ✓轴点归位:左小右大,位置即最终位置
- ✓单调性保证交换不漏不重,一个元素一回合
- ✓不变性是循环正确性的证明骨架
- ✓复杂度由轴点是否均衡决定
课后思考
先合上笔记自己想,再看参考答案——这些问题没有唯一解。
参考答案从成本与效果权衡:随机化让最坏情况难以被针对构造;端点实现最简单。取中间元素完全可行,某些有序输入上反而更均匀,可对照单调性一页验证。
参考答案每次划分都极度偏斜,递归深度退化到 O(n),总时间 O(n²)。提示:可从查找交换的节奏入手,思考如何让相等元素分摊到两侧。
参考答案可以。找出你希望始终为真的性质(如前段全是奇数),再用双指针维护它。这正是不变式方法的价值:先定性质,再推操作。