您的位置:首页 > 其它

二叉堆的添加及删除元素方法实现

2017-10-21 10:38 423 查看
本次以最大堆来讨论二叉堆的添加以及删除元素的方法,对于最大堆,一定满足两个条件:

  1. 二叉堆中的父节点的值一定大于其子节点的值。

  2.二叉堆一定为一颗满二叉树。

根据上面对于二叉堆的特点,我们可以很简单的找到给二叉堆添加元素的方法,首先二叉堆实际上是以数组来存储的,并且父节点的索引与子节点的索引都相互存在着一定的关系,因此对二叉堆的操作实际上就是对数组的操作。

首先我们来考虑给二叉堆添加元素的方法实现:

给二叉堆添加元素时,在数组的后一个元素加入其值,然后判断该元素是否在正确的位置上,即是否满足其值要小于其父节点的值,不满足的话则需要调换其位置。

例如如下图中,我们在数组11号中添加了一个值为52的元素,但其值要比其父节点还大,因此就破坏了二叉堆的特性,此时,我们只需要把插入的节点和其父节点调换一下位置即可。我们把向上与父节点调换位置的操作称为shiftup。



然后接下来只要一直进行shift的循环操作,使其添加的节点能找到属于自己正确的位置,则停止与父节点的调换。



以下为shift代码的具体实现:

void shiftup(int index)//index为添加的新元素在数组中的索引
{
while(index>1&&data[index]>data[index/2])//防止数组越界操作以及判断新节点是否大于其父节点
{
swap(data[index],data[index/2]);//如果大于则不满足二叉堆的条件,交换之
index/=2;//index更新其为父节点所在的索引(因为与父节点的值进行了调换)
}
}

我们接下来向二叉堆中插入5个随机值,然后看这5个值是否按照我们的预期正确的排列成了一个最大二叉堆。



我们可以在图纸上画出一颗二叉堆来,发现其完全满足条件。

接下来我们来考虑一下二叉堆的删除方法:

对于二叉堆来说,每次删除都是删除堆顶的元素,最大或者最小的元素,本次我们以最大堆来讨论:

对于最大堆来说,删除堆顶的元素,则堆顶的元素空缺的位置由整个堆的最后一个元素放到堆顶即可,这样还可以满足二叉树的完全性,然后把count减一个单位(count指向最后一个元素),此时数组就不会访问到最后一个被移到堆顶的元素了。

接下来我们在看如何调整被移到堆顶的元素的位置,假设我们称被移到堆顶的元素为替代位,则我们看替代位是否满足二叉堆的条件,即其值必须要大于它的根节点的值,如果不满足则需要向下与真正满足当父节点的节点进行替换,如果该替换位下面有两个子节点,则应该取二者之间的最大者与替换位进行替换,只有这样替换后才能满足父节点大于两个子节点的要求。对于像这样向下移动位置我们称其为shiftdown操作。

例如下图中替代位的值为52,根本不满足二叉堆的特性,因此我们将其与较大的子节点30进行替换。



以下为代码的具体实现:

item extractmax()//删除堆顶元素的操作
{
item ret=data[1];
swap(data[1],data[Count]);//把最后一个元素替换到堆顶
Count--;//更新数组的界限
shiftdown(1);//对堆顶元素进行shiftdown操作
return ret;
}

void shiftdown(int n)
{
while(2*n<=Count)//保证n不是叶子节点,叶子节点无子节点,防止越界访问
{
int j=2*n;//j指向子节点中的大者,默认为左孩子
if(j+1<=Count&&data[j+1]>data[j])//如果存在右孩子并且右孩子比左孩子还大
{
j++;//j就指向右孩子
}
if(data
>data[j]) break;//父节点比子节点中的大者还要大,满足二叉堆的条件
else
{
swap(data
,data[j]);//不满足条件则向下交换位置
}
n=j;//更新索引
}
}

我们接下来看一下二叉堆是否正确的进行了删除操作:



此时,二叉堆的堆顶最大的元素97已经被删除,并且剩下的4个元素仍然满足二叉堆的条件.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: