• 堆是完全二叉树的一种。

    所谓完全二叉树,就是每一个有孩子的节点一定有左孩子的二叉树

    举几个例子

        

     上面都是完全二叉树,最后一个是满二叉树,也是完全二叉树

     而下面的就不是

    完全二叉树的结构方便存储。若我们设一个节点的编号为i,那么不难发现它的左孩子是2i,右孩子是2i+1,它的父亲是i/2(整除),这方便我们用一维数组模拟。

    小根堆:

    对于任何一个节点i来说,a[i/2]<=a[i]且a[i]<=a[2*i],a[i]<=a[2*i+1](如果存在左右孩子的话)

    即每个节点的值必定大于等于其父节点,小于等于其子节点。

    大根堆:

    将小根堆反过来即为大根堆。

    不难看出,堆是要动态维护的。所以我们如何将一个数加入到堆里/从堆里取出呢?

    加入(这里是小根堆):

     1.  在堆尾先加入一个元素,并将该节点置为当前节点i。

      2. 将i与i/2比较,如果小于,就交换,并将当前节点编号改为i,继续如此比较。如果大于,就结束。(我们称之为上浮)

    int cnt=0;
    void put(int x)
    {  a[++cnt]=x;
       int m=cnt;
       while(m>=1)
       {int next=m/2;
         if(a[m]>=a[next])break;//如果满足小根堆,就停止循环 
         swap(a[m],a[next]);
         m=next;
       }
    }

    大根堆的加入就把>=改为<=即可

    取出:

      1.将根节点取出,并将a[cnt]放到根节点的位置上。

      2.比较该节点的两个儿子(特判没有儿子的情况),将该节点与较小的儿子比较,如果大于,就交换,继续如此比较。如果小于,就停止。

    int get()
    {int m,next,r;
      r=a[1];
      a[1]=a[cnt--];
      while(m*2<=cnt)
      {next=m*2;
        if(a[next]>a[next+1]&&next+1<=cnt)next++;//如果右儿子比左儿子小并且右儿子存在,
    //就比较当前点和右儿子
    if(a[m]<a[next])break; swap(a[m],a[next]); m=next; }
    return r;//这里是取出,上面是维护堆 }

    大根堆依旧是将比较符号改过来。

    应用:堆排序。

    例题:合并果子瑞瑞的木板快速排序

  • 相关阅读:
    Linux基础命令(一)
    You've made choice
    protege推理
    字符编码
    第二次作业
    数据类型-集合set
    数据类型-元组&字典
    数据类型-列表
    数据类型-数值&字符串
    流程控制之for循环
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/10776748.html
Copyright © 2020-2023  润新知