Article
算法导论-CH7-快速排序
算法导论-CH7-快速排序,待补充摘要。
- 算法导论(第四版)第七章:快速排序 前言 - 千葉原的文章 - 知乎 https://zhuanlan.zhihu.com/p/548622761
- 算法导论(第四版)第七章:快速排序 第一节:快速排序的说明 - 千葉原的文章 - 知乎 https://zhuanlan.zhihu.com/p/548700769
- 算法导论(第四版)第七章:快速排序 第二节:快速排序的性能 - 千葉原的文章 - 知乎 https://zhuanlan.zhihu.com/p/548906646
- 算法导论(第四版)第七章:快速排序 第三节:快速排序的随机化版本 - 千葉原的文章 - 知乎 https://zhuanlan.zhihu.com/p/549118974
- 算法导论(第四版)第七章:快速排序 第四节:快速排序的分析 - 千葉原的文章 - 知乎
https://zhuanlan.zhihu.com/p/549267719
- 【【算法分析设计速成课】各种排序:选择,冒泡,归并,快速】 https://www.bilibili.com/video/BV1DdrHBUEpX/?share_source=copy_web&vd_source=27abef6992749c2b76e3f7b2a2c835b5
第七章 快速排序 (QuickSort) 学习笔记
1. 快速排序概述
快速排序是一种经典的原地排序算法(In-place Algorithm),其核心思想是分治法(Divide and Conquer)。
- 最坏运行时间:
- 平均运行时间:
- 空间复杂度:(递归调用的栈空间)
2. 7.1 快速排序的说明与划分机制
快速排序的关键在于 PARTITION(划分) 程序,它实现了对子数组 的原地重排。
2.1 划分逻辑简述
- 选择 Pivot:选择一个基准值(通常选 )。
- 双指针遍历:使用 和 两个指针。
- 指针 扫描数组,如果 ,则将其交换到左侧。
- 指针 维护“小于等于 pivot”区域的边界。
- 重构区域:最终数组被划分为三个区域:
[小于等于 pivot 区域] [pivot] [大于 pivot 区域]

2.2 伪代码实现
QUICKSORT(A, p, r)
if p < r
q = PARTITION(A, p, r)
QUICKSORT(A, p, q - 1)
QUICKSORT(A, q + 1, r)
PARTITION(A, p, r)
x = A[r] # 枢轴 (pivot)
i = p - 1 # i 是小于等于 x 区域的最后一个元素的下标
for j = p to r - 1
if A[j] ≤ x
i = i + 1
exchange A[i] with A[j]
exchange A[i + 1] with A[r]
return i + 1 # 返回 pivot 的新位置
2.3 思考题 7.1-2:全相同元素处理
问题:当数组 中元素全相同时,PARTITION 返回的 是什么?如何修改使得此时返回 ?
解答:
- 现状:若元素全相同,
if A[j] ≤ x永远成立,i会增加到 ,最终返回 。这会导致最坏情况。 - 改进:通过计数判断是否全相同。
PARTITION_MODIFIED(A, p, r)
x = A[r]
i = p - 1
count = 0
for j = p to r - 1
if A[j] <= x
if A[j] == x: count = count + 1
i = i + 1
exchange A[i] with A[j]
if count == r - p: # 说明所有元素都等于 pivot
return floor((p + r) / 2)
exchange A[i + 1] with A[r]
return i + 1
3. 7.2 快速排序的性能与误区纠正
3.1 性能核心点
快排的性能高度取决于数组划分是否均匀,这直接受 pivot 选择的影响。
3.2 深度思考:为什么不是一直都是 ?
误区:认为“每一轮都要比较 次,所以总时间是 ”。
纠正:
- 一轮比较次数:当前子数组长度为 时,比较次数约为 。
- 分治的魔力:
- 最坏情况:每次划分产生 和 。总比较:。
- 最好情况:每次划分产生 和 。总比较: 每一层总和都是 ,共有 层。总时间为 。
- 直观理解:快排越“混乱”越快;若数据已经有序且 pivot 选得不好,反而最慢。
3.3 具体案例分析
7.2.1 最坏情况 (Worst-case)
当划分产生规模为 和 的子问题时:
- 典型案例:已排序数组选第一个或最后一个作为 pivot。
7.2.2 最好情况 (Best-case)
当划分产生规模均为 的子问题时:
7.2.3 平衡划分 (Balanced Partition)
即使划分比例不完美(如 9:1):
其递归树深度依然是 ,故运行时间仍为 。这说明只要划分是常数比例的,算法就很快。

3.4 相关练习题
- 7.2-2:全相同元素数组。划分产生 和 ,递归式 ,结果为 。
- 7.2-3:降序排序数组。划分产生 和 ,同上,结果为 。
4. 7.3 快速排序的随机化版本
为了避免在特定输入下(如已排序数组)触发最坏情况,我们引入随机性。
4.1 随机化算法
在划分前,随机选择一个元素与 交换。
RANDOMIZED-PARTITION(A, p, r)
i = RANDOM(p, r)
exchange A[r] with A[i]
return PARTITION(A, p, r)
RANDOMIZED-QUICKSORT(A, p, r)
if p < r
q = RANDOMIZED-PARTITION(A, p, r)
RANDOMIZED-QUICKSORT(A, p, q - 1)
RANDOMIZED-QUICKSORT(A, q + 1, r)
4.2 思考题
- 7.3-1:为什么分析期望运行时间?
- 因为随机化不改变最坏情况(依然可能运气极差抽到最小),但极大降低了最坏情况发生的概率。期望值代表了现实中最典型的表现。
- 7.3-2:RANDOM 被调用次数?
- 无论最好最坏,总会调用 次。因为每个元素都有机会被选作枢轴,且递归树总共有 个节点。
5. 7.4 快速排序的严格数学分析
5.1 最坏情况代入法证明
猜测 :
代入:(当 足够大)。 结合 证明,得出最坏情况为 。
5.2 关键引理证明(思考题 7.4-3)
问题:证明 在 或 时取最大。 证明:
- (开口向上)
- 极小值在 处。最大值必然在区间端点 或 处取得。即 。
5.3 期望时间分析与指示器变量(7.4-4)
设 为指示器随机变量,代表 与 是否发生过比较。
通过调和级数性质:
6. 7.4-5 实践优化:快排与插入排序结合
策略:当子数组规模小于 时停止递归,最后对整个数组进行一次插入排序。
运行时间证明:
- 快排部分:递归树深度减少,复杂度为 。
- 插入排序部分:共 个长度为 的块。总时间 。
- 总时间:。
- 选择 :理论上应选择满足 的 ,实际上需通过实验测试得出隐藏常数的最优解。
例题
7.1-1
画图说明PARTITION在数组 A=⟨13,19,9,5,12,8,7,4,21,2,6,11⟩ 上的操作过程。
解答:
对应第三版7.1-1。

7.2-1
运用代入法证明 的解为 。
解答:
对应第三版7.2-1。
猜测 ,则
其中 。