数组下标从1开始
堆是一个完全二叉树,故可以用数组模拟,数组下标从1开始,节点下标为x时,左节点为2x,右节点为2x+1。
例如:第一个节点的数组下标为1,左节点为2,右节点为3
堆主要有两个方法,down()和up(),堆的任何操作都可以用这两个方法实现,时间复杂度都为O(logn)
堆可以有下图这几种操作方式,以最小堆为例
删除最小值的思想是:因为最小值在数组中处于第一个位置,所以删除很不方便,此时可以用最后一个节点的值(下表为size)去覆盖要删除的值,然后对整个堆进行down()操作
删除任意一个元素:同理也是用最后一个节点去覆盖该节点,但是因为不确定删除的节点值和最后一个节点值哪个大,所以可以对修改后的堆实行down()和up()操作
如果删除节点<最后一个节点,那么堆进行down()
如果删除节点>最后一个节点,那么堆进行up()
所以说虽然写了down()和up()两种操作,但程序实际上只会执行一个
#include <iostream>using namespace std;const int N = 100010;int h[N],cnt;int n,m;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(t!=u) {swap(h[t],h[u]);down(t);}}void up(int u){while(u/2 && h[u/2] > h[u]){swap(h[u],h[u/2]);u /= 2;}}int main(){cin>>n>>m;for (int i = 1; i <= n; i ++ ) cin>>h[++cnt];for (int i = n/2; i; i--) down(i);while(m--){cout<<h[1]<<" ";h[1]=h[cnt--];down(1);}return 0;}
