【二叉堆】二叉堆的实现

一.简介

二叉堆支持插入、删除、查询最值,和stl库中的优先队列类似。相比优先队列,二叉堆还可以支持删除特定结点的操作,但是写法相比直接调用stl库的优先队列繁琐很多,因此应用不多。

不过本着学习的心态,还是有必要一看的:

二叉堆是一个满足“大/小根堆”性质的完全二叉树。

大根堆的任意子结点的权值都小于父结点权值
小根堆的任意子结点的权值都大于父结点权值

记忆方法很简单,小根堆顾名思义根结点权值比较小,大根堆顾名思义根结点权值比较大

二.实现

可以用一个数组来实现二叉堆。采取层序遍历从左到右的顺序给结点编号:

根据完全二叉树的性质,若一个结点的编号为p,则其父结点为p/2(这里的除是整除),其子节点为p×2和p×2+1(如果存在结点的话)

插入删除操作都在数组末尾进行:

插入操作:先将元素加入数组末尾,然后依据二叉堆的性质进行调整,时间复杂度 O ( log ⁡ N ) O(\log N) O(logN)

删除操作:先将元素与数组末尾交换,删除数组末尾,然后依据二叉堆的性质对元素进行调整

三.具体代码(大根堆)

用一个变量cnt分配结点
用数组heap储存二叉堆

int heap[maxn];
int cnt=1;

1.初始化

void init(){
  memset(heap,0,sizeof(heap));
  cnt=1;
}

2.调整

向上调整函数

void up(int p){
   while(p>1){
     if(heap[p]<=heap[p/2])// 满足大根堆,不需要调整  
        break;
     swap(heap[p],heap[p/2]);
     p/=2;
   }
}

向下调整函数

void down(int p){
   int s=p*2;
   while(s<cnt){
      if(s<cnt-1&&heap[s]<heap[s+1]) //取子结点中较大的 
         s++; 
      if(heap[s]<=heap[p]) break;
      swap(heap[p],heap[s]);
      p=s;s=p*2;
   }
}

3.插入

void Insert(int x){
   heap[cnt]=x;
   up(cnt);
   cnt++;
}

插入一个结点,先将其插入到数组的末尾(即二叉树的末尾),然后向上调整即可

4.删除

void Remove(int k){
    heap[k]=heap[--cnt];
    up(k); down(k);
}

删除结点,先将其与数组末尾交换,然后再调整。

删除堆顶是删除的特殊情况,因为在堆顶不需要向下调整:

void Extract(){
    heap[1]=heap[--cnt];
    down(1);
}

5.取最值

二叉堆堆顶heap[1] 存放的就是最值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值