来源:互联网 发布:专业美工电脑配置 编辑:程序博客网 时间:2024/04/29 23:53

首先要明确一点:堆是一种数据结构,而不能算是一种算法,并且堆这种数据结构是基于书这种数据结构的,接下来我将要写的是堆的向下转换和向上转换。

究竟什么是堆???

堆其实就是一种带有条件的完全二叉树,堆分为两种:一,最小堆     二,最大堆,当父节点比孩子节点都要小时为最小堆,当父节点比孩子节点都要大时为最大堆。

堆有很多用途,并且有时候对效率有非常大的提升,接下来我就以《啊哈算法》中的例子来解析一下堆这种数据结构。

例子:有如下一个树:


这就是一种最小堆,根据上面我们讲的堆得原理,我们可以知道在最小堆中,堆得根节点就是堆中的最小的一个节点,(注意:在一棵二叉树中 如果父节点时k 则其左孩子是2*k 右节点是2*k+1),如果我们求这些节点中的最小的一个数,并且再插入一个数,我们应该怎么做呢?

最开始的想法(完全就不往数这方面想),我会把这些节点存到数组中,然后用for循环找到最小值,然后再把最小值删除,再插入一个新值,这样的话,时间复杂度就是O(N),其实对于这样的问题,用堆这种数据结构是比较好的,具体怎么用呢?

首先我们可以把这样一个堆(其实就是上图的树),存入数组中,数组的第一个元素就是根节点,即最小的节点,(是不是还在等着循环? 哈哈 不用循环最小元素已经找到啦),接下来的问题就是插入一个新元素啦,这一点我们需要注意,因为为了下一次这个堆的根节点还是最小节点,我们在插入新的节点后,还是要把这个树整理成一个堆,这就是重点要讲的向下转换问题。

如图所示;当我们把根节点取出来,在插入一个新的节点,就像下图这样:


我们会发现插入23后,这个树已经不再是堆了,如果想要变成最小堆,就必须要根据父节点总是比子节点小这个原理把23这个节点向下转换。

第一步:


和子孩子进行向下转换!

第二步:


再和右孩子进行转换!

最后一步:


可以发现,只需要三步,就重新弄成了一个最小堆,这意味着只需要三步,就可以取出两个最小值,如果用循环,我们需要循环两个N。

接下来是用代码实现:

用数组 p[50] 存放这个堆(也就是树)

void siftdown(int i)
{
int t,flag=0;//t是临时变量,flag是一个标记。
while(i*2<n&&flag==0)// 如果存在左孩子(因为是完全二叉树,所以可能没有右孩子),并且标记没有变化,就执行转换操作
{
if(p[i]>p[i*2])//如果父节点比左孩子大
t=i*2;//把较小的节点的下标给临时变量
else
t=i;
if(p[t]>p[i*2+1]&&i*2+1<n)//把找到的较小的节点再跟右孩子进行比较
{
t=i*2+1;
}// 上面几行就是找父节点和两个孩子节点哪一个最小,把最小节点的下标存入临时变量
if(t!=i)// 如果所求出的最小节点不是刚开始的节点,就进行交换,如果是刚开始的节点,就说明此节点符合最下堆得原理,就完成了转换,把标记转换为 1 

{
swap(t,i);

i=t;//把转换的节点进行更新,再进行下一次转换

}
else
flag=1;

}
}

这就是向下转换!

还有一种是向上转换,就是把一个新的节点插入到这颗堆的最后,如果不再是堆,就一步步的向上转换,使之再次成为一个堆,这也是在堆中插入新元素的算法。

直接上代码:

void siftup(int i)
{
if(i==1)//如果此节点就是根节点,就不用调整
return ;
while(i!=1&&flag==0)
{
if(p[i]<p[i/2])// 如果子节点小于父节点,则进行交换
{
t=i/2;
swap(i,t);//此函数要自己实现,交换的不是角标,而是值
i=t;
}
else
{
flag=1;
}
}
}

注意向上转换和向下转换的代码的不同:向下转换时,需要在父节点和孩子节点中找到一个最小的节点,,因为如果一个父节点有两个孩子节点,则转换的时候需要和较小的子节点进行转换,而向上转换时,只需要和父节点比较即可,因为如果此节点比父节点小,则一定比其兄弟节点小。

接下来就是怎么建立堆得问题!

一, 

假设有m个顶点

for(int i=1;i<=m;i++)

{

scanf("%d",&p[i]);

siftup(i);

}

二,

先把数存到数组中(其实就是一个树用数组存起来),然后再对每一个子树的父节点进行遍历和调整,直到最后形成一个堆。

代码如下:

for(int i=n/2;i>=1;i--)//如果一个完全二叉树树有n个节点,那么第一个非叶子节点是n/2

{

siftdown(i);

}

最后还有一个著名的堆排序算法,这个有时间再写!

此文改编自《啊哈算法》!

0 0
原创粉丝点击