每天学一个算法-快速排序(Quick Sort)

📘 快速排序(Quick Sort)

1. 问题定义

给定数组 (A1...n),目标是将其重排为:

A\[1\]≤A\[2\]≤⋯≤A\[n\]\]\[A\[1\] \\le A\[2\] \\le \\dots \\le A\[n\]\]\[A\[1\]≤A\[2\]≤⋯≤A\[n\]

2. 核心思想

快速排序基于:

🔹 分治(Divide and Conquer)

将问题递归拆解为两个子问题。

在本算法中具体体现为:

  1. 选择一个元素作为枢轴(pivot)
  2. 执行划分(partition)
  3. 对左右子数组递归排序

3. 核心术语(精确定义 + 可理解解释)

🔸 3.1 枢轴(Pivot)

定义:

用于划分数组的参考元素

作用:

将数组分为两部分:

\\text{左区间} \\le pivot \\le \\text{右区间}

理解:

pivot 是"分界值",它最终会被放到正确位置

🔸 3.2 划分(Partition)

定义:

对区间 (Al...r) 重排,使:

∀i\p, A\[j\]≥A\[p\]\]\[ \\forall i \< p,\\ A\[i\] \\le A\[p\] \\quad \\forall j \> p,\\ A\[j\] \\ge A\[p\] \]\[∀i\p, A\[j\]≥A\[p\]

关键点:

  • 只保证"左右关系正确"
  • 不保证内部有序

👉 这是最容易误解的地方

🔸 3.3 递归(Recursion)

定义:

函数调用自身解决子问题

在快排中的作用:

  • 对左区间继续排序
  • 对右区间继续排序

🔸 3.4 原地排序(In-place)

定义:

不依赖额外线性空间

快排特点:

  • 通过交换完成排序
  • 仅使用常数额外空间(不计递归栈)

🔸 3.5 稳定性(Stability)

定义:

相等元素排序后相对顺序是否保持

结论:

快速排序不稳定

4. 算法结构

4.1 主过程

text 复制代码
QuickSort(A, l, r):
    if l < r:
        p = Partition(A, l, r)
        QuickSort(A, l, p-1)
        QuickSort(A, p+1, r)

4.2 划分函数(Lomuto)

text 复制代码
Partition(A, l, r):
    pivot = A[r]
    i = l - 1
    for j = l to r-1:
        if A[j] ≤ pivot:
            i = i + 1
            swap(A[i], A[j])
    swap(A[i+1], A[r])
    return i + 1

5. 核心机制(教学重点)

5.1 三个逻辑区间

在 partition 过程中,数组被划分为:

区间 含义
(Al..iAl..iAl..i) ≤ pivot
(Ai+1..j−1Ai+1..j-1Ai+1..j−1) > pivot
(Aj..r−1Aj..r-1Aj..r−1) 未处理

5.2 循环不变量(Loop Invariant)

在每轮循环开始时成立:

A\[l..i\]≤pivot,A\[i+1..j−1\]\>pivot\]\[ A\[l..i\] \\le pivot,\\quad A\[i+1..j-1\] \> pivot \]\[A\[l..i\]≤pivot,A\[i+1..j−1\]\>pivot

意义:

  • 保证算法过程始终正确
  • 是证明正确性的关键工具

5.3 Partition 的本质

不是排序,而是:

把一个元素(pivot)放到它最终应该在的位置

6. 正确性(简要证明)

6.1 Partition 正确性

循环结束后:

  • 左侧元素全部 ≤ pivot
  • 右侧元素全部 ≥ pivot
  • pivot 被交换到正确位置

6.2 递归正确性

基于归纳法:

  • 子问题规模更小
  • 子问题正确排序
  • 整体有序

7. 时间复杂度

7.1 递推式

T(n)=T(k)+T(n−k−1)+Θ(n)\]\[ T(n) = T(k) + T(n-k-1) + \\Theta(n) \]\[T(n)=T(k)+T(n−k−1)+Θ(n)

7.2 三种情况

情况 复杂度 原因
最优 (n \log n) 划分均匀
最坏 (n^2) 划分极端
平均 (n \log n) 随机分布

🔹 为什么是 (n \log n)

  • 每层处理 (n) 个元素
  • 层数约为 (\log n)

8. 空间复杂度

来源:递归调用栈

情况 空间复杂度
平均 (\log n)
最坏 (n)

9. 枢轴选择对性能的影响

🔸 9.1 固定选择

  • 简单
  • 易退化

🔸 9.2 随机选择

作用:

  • 打乱输入结构
  • 避免极端划分

🔸 9.3 三数取中

降低偏斜划分概率

10. 三路划分(进阶)

动机:

存在大量重复元素时:

  • 普通快排效率下降

解决:

划分为:

\pivot\]\[ \< pivot \\quad = pivot \\quad \> pivot \]\[\pivot

效果:

减少递归规模

11. 与其他排序对比

算法 时间 空间 稳定
快排 平均 (nlog⁡nn \log nnlogn) 原地
归并 (nlog⁡nn \log nnlogn) 额外空间
堆排 (nlog⁡nn \log nnlogn) 原地

12. 常见错误

❌ 错误1:认为 partition 后数组已排序

👉 实际只完成"分区"

❌ 错误2:递归区间写错

错误:

QuickSort(A,l,p)\]\[ QuickSort(A, l, p) \]\[QuickSort(A,l,p)

正确:

QuickSort(A,l,p−1)\]\[QuickSort(A, l, p-1)\]\[QuickSort(A,l,p−1)

❌ 错误3:不理解 i 的含义

i 表示:

复制代码
			$\text{"≤ pivot 区域的右边界"}$

13. 关键结论

  1. 快排核心是 partition
  2. pivot 决定效率
  3. 平均复杂度 (n \log n)
  4. 非稳定排序
  5. 原地算法
相关推荐
2401_868534783 小时前
【无标题】
数据结构·r语言
Mr. zhihao4 小时前
Redis五大高级数据结构:原理-场景-底层-横向对比
数据结构·redis
QiLinkOS4 小时前
【从实验室到商业战场:发明专利如何重塑科技与企业的共生生态】
大数据·c语言·数据结构·c++·人工智能·单片机·算法
如此这般英俊4 小时前
手撕Claude Code—第一章 agent-loop
数据结构·人工智能·语言模型·自然语言处理
小白兔奶糖ovo5 小时前
【Leetcode】231. 2的幂
linux·算法·leetcode
xiaoxiaoxiaolll5 小时前
《Light: Science & Applications》合并BIC实现80倍阈值单模运行:超紧凑光子晶体激光器新突破
人工智能·算法·机器学习
Peter·Pan爱编程5 小时前
14. Lambda 表达式:随手可写的函数对象
c++·算法·ai编程
-To be number.wan5 小时前
算法日记 | 暴力枚举
学习·算法
s_w.h5 小时前
【 linux 】动静态库的制作
linux·运维·服务器·算法·bash
过期动态6 小时前
【LeetCode 热题 100】接雨水
java·数据结构·算法·leetcode·职场和发展