二叉堆的添加及删除元素方法实现
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个元素仍然满足二叉堆的条件.
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个元素仍然满足二叉堆的条件.
相关文章推荐
- JS实现添加,替换,删除节点元素的方法
- JavaScript实现向select下拉框中添加和删除元素的方法
- ADO.NET使用带参数方法实现添加、删除和修改数据
- Extjs4 实现两个DataView之间元素的拖拽添加及删除
- JavaScript实现添加、查找、删除元素
- php+mysqli预处理技术实现添加、修改及删除多条数据的方法
- AS3)实现过滤数组/删除数组中的相同元素(记录6种方法)
- 实现在一个数组指定位置添加元素和删除元素的功能
- JavaScript实现向OL列表内动态添加LI元素的方法
- JQuery实现动态添加删除评论的方法
- JS数组array元素的添加和删除方法代码实例
- JS数组array元素的添加和删除方法代码实例
- python实现从字典中删除元素的方法
- php+mysqli预处理技术实现添加、修改及删除多条数据的方法
- JS 添加删除元素的实现代码
- JS 添加删除元素的实现代码
- (转载)php数组添加、删除元素的方法
- js实现对table动态添加、删除和更新的方法
- (AS3)实现过滤数组/删除数组中的相同元素(记录6种方法)