二叉堆
堆
如何手写一个堆?
首先堆是一颗完全二叉树,结合完全二叉树的性质我们可以利用数组来存储一棵树。每个结点的编号从1开始。
插入一个数。
heap[++size] = x; up(size);
求集合当中的最小值。
heap[1]
删除最小值。
heap[1] = heap[size]; size--; down(1);
用最后一个节点覆盖第一个节点然后做down(1)
操作删除任意一个元素。
heap[k] = heap[size]; size--; down(k); up(k)
删除结点中的任意一个值,利用最后一个结点进行覆盖。然后进行up(k), down(k)
操作.修改任意一个元素。
heap[k] = x; up(k); down(k);
// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int h[N], ph[N], hp[N], size;
// 交换两个点,及其映射关系
void heap_swap(int a, int b)
{
swap(ph[hp[a]],ph[hp[b]]);
swap(hp[a], hp[b]);
swap(h[a], h[b]);
}
//down操作
void down(int u) {
int t = u; //用t暂存当前节点的值
if (u * 2 <= sizes && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= sizes && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t) {
swap(h[u], h[t]);
down(t); //继续向下调整
}
}
//up操作
void up(int u) {
//up操作,如果当前结点的父节点值比当前结点大则交换两个结点的值然后接续向上处理进行Up操作
while(u / 2 && h[u / 2] > h[u]) {
swap(h[u], h[u / 2]);
u /= 2;
}
}
//删除结点k
void remove(int k) {
h[k] = h[sizes--];
up(k), down(k);
}
下面给出两道二叉堆模板题用来练习: