堆简介

堆是一棵完全二叉树,其每个节点都有一个键值,且每个节点的键值都大于等于/小于等于其父亲的键值。

每个节点的键值都大于等于其父亲键值的堆叫做小根堆,否则叫做大根堆。STL 中的 priority_queue 其实就是一个大根堆。

(小根)堆主要支持的操作有:插入一个数、查询最小值、删除最小值、合并两个堆、减小一个元素的值。

用数组模拟小根堆

小根堆的特点:每个点都小于等于左右儿子,因此堆顶是最小值。

存储:
堆顶:1
x的左儿子:2x,右儿子:2x+1.

两个核心操作:
up(x)和down(x).
其中,down(u)使h[u]处的点往下沉到形成堆,up(u)使u处的点往上走至形成堆为止。

以上的操作组合可以完成下列操作:
(1)插入一个数:heap[++cnt]=x;up(cnt);
(2)求集合中的最小值:heap[1]
(3)删除最小值:heap[1]=heap[cnt];down(1);cnt--;
(4)删除任意元素:heap[k]=heap[cnt];cnt--;down(k);up(k);
(5)修改任意元素:heap[k]=x;up(k);down(k);

代码模板

朴素版堆

//down(x)
void down(int u){
    int t=u;
    if(2*u<=cnt&&h[2*u]<h[t]) t=2*u;
    if(2*u+1<=cnt&&h[2*u+1]<h[t]) t=2*u+1;
    if(u!=t){
        swap(h[u],h[t]);
        down(t);
    }
}
//up(x)
void up(int u){
    while(u/2&&h[u/2]>h[u]){
        swap(h[u],h[u/2]);
        u=u>>1;
    }
}
//o(n)建堆
 for(int i=n/2;i;i--) down(i);

带映射版

int h[N],ph[N],hp[N],cnt;
//hp[],ph[]存储的是映射关系
//带映射版swap
void heap_swap(int u,int t){
    swap(ph[hp[u]],ph[hp[t]]);
    swap(hp[u],hp[t]);
    swap(h[u],h[t]);
}
//down(x)
void down(int u){
    int t=u;
    if(2*u<=cnt&&h[2*u]<h[t]) t=2*u;
    if(2*u+1<=cnt&&h[2*u+1]<h[t]) t=2*u+1;
    if(u!=t){
        heap_swap(u,t);
        down(t);
    }
}
//up(x)
void up(int u){
    while(u/2&&h[u/2]>h[u]){
        heap_swap(u,u/2);
        u=u>>1;
    }
}
上一篇:唧唧Down(B站视频下载) 彻底解决你的B站视频下载问题


下一篇:补题记录B. Let's Go Hiking