堆
来源:互联网 发布:专业美工电脑配置 编辑:程序博客网 时间: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);
}
最后还有一个著名的堆排序算法,这个有时间再写!
此文改编自《啊哈算法》!
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- 堆
- FFMPEG 解码RTP+h264
- 基于Ubuntu 14.04.2安装cuda-7.0-27
- 1171 Big Event in HDU
- 黑马程序员——Java中的GUI
- C++ auto_ptr智能指针的用法
- 堆
- jQuery实现tabs(标签页/选项卡)Demo
- Android studio 使用 facebook 开源图片库 Fresco
- 在U盘上安装RaspberryPI
- 畅通工程再续
- UI开发----简单通讯录的实现
- ZOJ 3332 Strange Country II
- h264解码小程序
- 【我就看看不说话】UIAppearance