堆(Heap)
声明大根堆与小根堆
1 2 3 4 5 6 7 | |
常用的操作
C++ 算法竞赛中的堆与优先队列
在算法竞赛里,堆(Heap) 是一种完全二叉树结构,核心特性是能快速取出最值;优先队列(priority_queue) 是 C++ STL 封装好的堆,不用手写堆,直接用就行,是高频工具。
一、堆是什么?
堆分两种: 1. 大根堆:堆顶是最大值 2. 小根堆:堆顶是最小值
满足性质:
- 父节点 ≥ 子节点(大根堆)
- 父节点 ≤ 子节点(小根堆)
- 是完全二叉树,可用数组存储
常用操作(时间复杂度均为 O(log n)):
- 插入元素
- 删除堆顶
- 取堆顶最值
二、STL 优先队列 priority_queue
q.top()取堆顶q.pop()删除堆顶q.push(x)插入q.empty()判断是否为空q.size()大小
示例:
1 2 3 4 5 6 7 8 9 10 | |
3. 自定义结构体优先队列
竞赛常需要按某个字段排序,比如结构体 Node 按 val 从小到大:
1 2 3 4 5 6 7 8 9 | |
记住规则:
return a < b→ 大根堆return a > b→ 小根堆
三、常用操作速查表
| 操作 | 代码 |
|---|---|
| 定义大根堆 | priority_queue<int> q; |
| 定义小根堆 | priority_queue<int, vector<int>, greater<int>> q; |
| 插入元素 | q.push(x); |
| 取堆顶 | q.top(); |
| 删除堆顶 | q.pop(); |
| 是否为空 | q.empty(); |
| 元素个数 | q.size(); |
四、堆的经典应用场景
-
Top K 问题 求前 K 大/前 K 小,用堆 O(n log k) 解决。
-
贪心算法 每次选当前最优(最值),比如 Huffman 编码、合并果子、任务调度。
-
Dijkstra 最短路 用优先队列优化,从 O(n²) 降到 O(m log n)。
-
动态维护中位数 大根堆存左半部分,小根堆存右半部分。
-
多路归并 多个有序数组归并,用堆取当前最小。
五、手写堆(必要时)
STL 优先队列不支持删除任意元素,某些题必须手写堆。
手写堆常用数组实现,核心是 up(上浮)、down(下沉)。
简单小根堆框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
六、竞赛小技巧
- 求最小用小根堆,求最大用大根堆
- 多关键字排序直接重载结构体
< - Dijkstra 必用小根堆优化
- STL 优先队列不能遍历,要输出只能 pop
- 遇到“可删除堆”,一般用懒删除:标记失效元素,取到再扔掉