📘 堆排序(Heap Sort)
1. 问题定义
给定数组 (A[1...n]),要求:
A\[1\]≤A\[2\]≤⋯≤A\[n\]\]\[ A\[1\] \\le A\[2\] \\le \\dots \\le A\[n\] \]\[A\[1\]≤A\[2\]≤⋯≤A\[n\]
2. 核心思想
堆排序的核心不是分治,而是:
利用"堆(Heap)这种特殊数据结构"进行排序
3. 核心术语
3.1 堆(Heap)
定义:
一种完全二叉树,满足:
👉 堆性质(Heap Property)
🔹 最大堆(Max Heap)
A\[parent\]≥A\[child\]\]\[ A\[parent\] \\ge A\[child\] \]\[A\[parent\]≥A\[child\]
👉 根节点是最大值
🔹 最小堆(Min Heap)
A\[parent\]≤A\[child\]\]\[ A\[parent\] \\le A\[child\] \]\[A\[parent\]≤A\[child\]
👉 根节点是最小值
3.2 完全二叉树(Complete Binary Tree)
定义:
- 除最后一层外,每层都满
- 最后一层从左到右填充
为什么重要?
👉 可以用数组表示
3.3 数组表示(关键)
对于节点 (i):
- 左子节点:(2i)(2i)(2i)
- 右子节点:(2i+1)(2i + 1)(2i+1)
- 父节点:(⌊i/2⌋)(\lfloor i/2 \rfloor)(⌊i/2⌋)
3.4 堆化(Heapify)
定义:
调整某个节点,使其满足堆性质
本质:
把"不合法的节点"向下调整
4. 堆排序整体流程
Step 1:建堆(Build Heap)
将数组变成最大堆
Step 2:排序
重复:
- 交换堆顶和末尾元素
- 缩小堆范围
- 对根节点执行 heapify
一句话总结
每次取出最大值,放到数组末尾
5. 算法结构
5.1 主函数
text
HeapSort(A):
BuildMaxHeap(A)
for i = n downto 2:
swap(A[1], A[i])
heap_size -= 1
Heapify(A, 1)
5.2 Heapify
text
Heapify(A, i):
largest = i
if left child > A[i]:
largest = left
if right child > A[largest]:
largest = right
if largest ≠ i:
swap(A[i], A[largest])
Heapify(A, largest)
6. 核心机制(教学重点)
6.1 为什么堆能排序?
因为:
👉 最大堆的根节点是当前最大值
6.2 每一步发生了什么?
text
[堆] → 取最大值 → 放到末尾 → 剩下继续堆化
6.3 本质过程
不是"排序",而是:
不断从结构中"取最大值"
7. 建堆过程(必须讲)
7.1 为什么从 n/2 开始?
因为:
- 叶子节点本身已经满足堆性质
- 只需要调整非叶子节点
7.2 建堆代码
text
BuildMaxHeap(A):
for i = n/2 downto 1:
Heapify(A, i)
7.3 时间复杂度(关键点)
👉 不是 (O(n \log n))
而是:
O(n)\]\[ O(n) \]\[O(n)
为什么?
- 底层节点多,但调整成本低
- 上层节点少,但调整成本高
整体为线性复杂度
8. 示例(必须讲)
初始数组
text
[4, 10, 3, 5, 1]
建堆
text
10
/ \
5 3
/ \
4 1
排序过程
Step 1:
text
swap(10,1)
→ [1,5,3,4,10]
heapify:
text
→ [5,4,3,1,10]
继续重复,最终:
text
[1,3,4,5,10]
9. 时间复杂度
9.1 组成
- 建堆:(O(n))
- 每次 heapify:(O(\log n))
- 共 (n) 次
9.2 总复杂度
O(nlogn)\]\[ O(n \\log n) \]\[O(nlogn)
9.3 特点
👉 无最坏退化
10. 空间复杂度
O(1)\]\[ O(1) \]\[O(1)
👉 原地排序
11. 稳定性
❌ 不稳定
因为存在跨层交换
12. 与前两个算法对比(关键)
| 算法 | 核心机制 | 空间 | 稳定性 |
|---|---|---|---|
| 快排 | partition | 原地 | ❌ |
| 归并 | merge | O(n) | ✅ |
| 堆排 | heap | 原地 | ❌ |
13. 常见错误
❌ 错误1:搞错数组下标关系
必须记住:
text
left = 2i
right = 2i+1
❌ 错误2:Heapify写错
只调整一次不够
👉 必须递归
❌ 错误3:建堆方向错
必须从:
text
n/2 → 1
14. 关键结论
- 堆排序核心是 heapify
- 最大堆保证快速取最大值
- 时间复杂度稳定 (n log n)
- 空间复杂度最优(O(1))
15. 最小教学总结
堆排序的本质不是"比较排序",而是:
用一个结构(堆)不断取出最大元素