2020.2.6每日一题“二叉堆”

什么叫二叉堆

二叉树我们是了解的,但二叉堆又是什么呢

其实二叉堆就是完全二叉树,就是有左儿子就必定有右儿子

但二叉堆又并不完全等同于一棵完全二叉树,他有更多特别的性质

比如二叉堆的顶端一定是极端的(要么最大要么最小),哪一方面的极端要视具体题目而定

可能是权值,也有可能是优先级

通过堆顶极端的不同又可以分为大根堆(堆顶最大)和小根堆(堆顶最小)
在这里插入图片描述

每一个根节点都可以视为堆顶,因为对于堆的每棵子树都可以视为完全二叉树

堆的操作

二叉堆一般都通过"数组"来实现。数组实现的二叉堆,父节点和子节点的位置存在一定的关系。有时候,我们将"二叉堆的第一个元素"放在数组索引0的位置,有时候放在1的位置。当然,它们的本质一样(都是二叉堆),只是实现上稍微有一丁点区别。

假设"第一个元素"在数组中的下标为 0 的话,则父节点和子节点的位置关系如下:

(01) 父节点为i的左孩子的下标是 (2*i+1);

(02) 父节点为i的右孩子的下标是 (2*i+2);

(03) 父节点为i的父结点的下标是 floor((i-1)/2);

floor()意思是向下取整,即取不大于要求值的最大的那个整数值;

假设"第一个元素"在数组中的下标为 1 的话,则父节点和子节点的位置关系如下:

(01) 父节点为i的左孩子的下标是 (2*i);

(02) 父节点为i的右孩子的下标是 (2*i+1);

(03) 父节点为i的父结点的下标是 floor(i/2);

插入

当我们要往二叉堆中插入新的元素时,需要遵循待插入二叉堆的规则

如果是大根堆则要将最大的放在根节点,先将待插入元素放在堆底

将其与其根节点比较,若根节点比他小则交换,直到堆顶为止。

int swap(int &x,int &y)
{
    int t;
    t=x;
    x=y;
    y=t;
}
int a[1000];//堆
int size;//堆的大小
void insert(int n,int a[])
{
    a[size++]=n;
    cnt=size;//插入元素的位置
    while(cnt)
    {
        //假设这是一个小根堆
        int next=cnt/2;
        //找到父节点,因为此时的堆顶为a[1];若为a[0],则为cnt/2-1;上面提到过。
        if(a[next]>a[cnt])//如果根节点大于插入元素则交换
            swap(a[next],a[cnt]);//交换
        else
            break;
        cnt=next;
    }
}

删除

怎么删除?在删除的过程中还是要维护小根堆的性质

如果你直接删掉了,那就没有堆顶了,这个堆就直接乱了

所以我们要保证删除后这一整个堆还是个完好的小根堆

首先在它的两个儿子里面,找一个比较小的,和它交换一下,但是还是没法删除,因为下方还有节点,那就继续交换,直到下面没有节点了,这时候直接把它扔掉就好了

tput()
{
    swap(heap[size],heap[1]);
    size--;//交换堆顶和堆底,然后直接弹掉堆底
    int cnt=1;
    while((cnt*2)<=siz) //对该节点进行向下交换的操作
    {
        int next=cnt*2;//找出当前节点的左儿子
        if(next+1<=size&&heap[next+1]<heap[next])
            next++;//看看是要左儿子还是右儿子跟它换
        if(heap[next]<heap[cnt])
            swap(heap[cnt],heap[next]);//如果不符合堆性质就换
        else
            break;//否则就完成了
        cnt=next;//往下一层继续向下交换
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值