堆
堆的特点
- 插入一个数;
- 求集合中的最小值;
- 删除最小值;
以上是堆的最基本的特性,C++ STL 实现的小根堆支持上述操作。
- 删除任意一个元素;
- 修改如意一个元素;
以上两个特性 STL 堆无法直接实现,但是可以间接实现。
堆是一个完全二叉树。
以小根堆为例子,每个节点的值都小于等于两个子节点。所以根节点是集合的最小值。
STL 堆
STL 堆就是 优先队列。并且实现的堆是 小根堆。
定义:
#include <queue>
typedef pair<int, int> PII;
priority_queue<PII, vector<PII>, greater<PII>> heap;
利用 pair 的 first 来排序。每次返回一个 pair。
插入一个数:heap.push({x, y})
获得堆的最小值:heap.top()
。
删除堆的最小值:heap.pop()
。
手写堆
手写堆的存储
手写堆时,直接使用一个一维数组来存储,因为堆是一个完全二叉树。
根节点 heap[1]。
节点 x 的左儿子:2x
节点 x 的右儿子:2x + 1
**注意:下标从 0 开始。这是因为 0 的左儿子使用公式计算还是 0。**从 0 开始就不太方便了。
手写堆的两个基本操作
手写堆的所有功能都是通过这两个基本操作实现的:
down( x ) :将一个节点向上移。
up( x ) :将一个节点向下移。
down 与 up 都是与树的高度成正比的,所以时间复杂度是 O ( l o g n ) O(logn) O(logn) 的。
const int N = 100010;
int n, m;
int heap[N], size;
void down(int u) {
int t = u; // 用 t 存储三个节点(u 节点和它的两个子节点)中的最小值
if (u * 2 <= size && h[u * 2] < h[t]