什么叫二叉堆
二叉树我们是了解的,但二叉堆又是什么呢
其实二叉堆就是完全二叉树,就是有左儿子就必定有右儿子
但二叉堆又并不完全等同于一棵完全二叉树,他有更多特别的性质
比如二叉堆的顶端一定是极端的(要么最大要么最小),哪一方面的极端要视具体题目而定
可能是权值,也有可能是优先级
通过堆顶极端的不同又可以分为大根堆(堆顶最大)和小根堆(堆顶最小)
每一个根节点都可以视为堆顶,因为对于堆的每棵子树都可以视为完全二叉树
堆的操作
二叉堆一般都通过"数组"来实现。数组实现的二叉堆,父节点和子节点的位置存在一定的关系。有时候,我们将"二叉堆的第一个元素"放在数组索引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;//往下一层继续向下交换
}
}