数组下标从1开始

    堆是一个完全二叉树,故可以用数组模拟,数组下标从1开始,节点下标为x时,左节点为2x,右节点为2x+1。
    例如:第一个节点的数组下标为1,左节点为2,右节点为3

    堆主要有两个方法,down()和up(),堆的任何操作都可以用这两个方法实现,时间复杂度都为O(logn)

    堆可以有下图这几种操作方式,以最小堆为例
    删除最小值的思想是:因为最小值在数组中处于第一个位置,所以删除很不方便,此时可以用最后一个节点的值(下表为size)去覆盖要删除的值,然后对整个堆进行down()操作
    删除任意一个元素:同理也是用最后一个节点去覆盖该节点,但是因为不确定删除的节点值和最后一个节点值哪个大,所以可以对修改后的堆实行down()和up()操作
    如果删除节点<最后一个节点,那么堆进行down()
    如果删除节点>最后一个节点,那么堆进行up()
    所以说虽然写了down()和up()两种操作,但程序实际上只会执行一个
    image.png

    1. #include <iostream>
    2. using namespace std;
    3. const int N = 100010;
    4. int h[N],cnt;
    5. int n,m;
    6. void down(int u)
    7. {
    8. int t = u;
    9. if(2*u<=cnt && h[2*u] < h[t]) t=2*u;
    10. if(2*u + 1 <=cnt && h[2*u+1]<h[t]) t= 2*u+1;
    11. if(t!=u) {
    12. swap(h[t],h[u]);
    13. down(t);
    14. }
    15. }
    16. void up(int u)
    17. {
    18. while(u/2 && h[u/2] > h[u]){
    19. swap(h[u],h[u/2]);
    20. u /= 2;
    21. }
    22. }
    23. int main()
    24. {
    25. cin>>n>>m;
    26. for (int i = 1; i <= n; i ++ ) cin>>h[++cnt];
    27. for (int i = n/2; i; i--) down(i);
    28. while(m--)
    29. {
    30. cout<<h[1]<<" ";
    31. h[1]=h[cnt--];
    32. down(1);
    33. }
    34. return 0;
    35. }