二叉堆是一种高级的数据结构,用来动态
维护一个序列中的最值和对某一个数的删除或插入。堆满足下列性质:
以上就是一些关于堆的相关操作,时间效率都是O(logn)的。因此堆是一种非常有用的数据结构!
1,堆是一棵完全二叉树。(因此可以用数组来表示且
不浪费空间
)
2,堆的每一个父亲节点的值均≥(大根堆)或≤(小根堆)其左右孩子的值。(下面若没有注明,均讨论大根堆)
下面来看一下堆的相关操作:
【最值
】
最值就不用说了吧,直接输出根节点就行了。因为根节点都大于等于其左右孩子,而它的左右孩子又大于等于其左右孩子……。
【插入】
为了方便,插入时一般在数组的尾部,但插入后会出现一些不符合堆的性质的情况:h[ p ]>=h[ father(p) ],这是我们把它们交换,就可以维护性质了。但交换后还是可能出现违背性质的情况,
所以,我们要从下往上进行交换。众所周知,father(p)=p/2,因此可以用p/2的步骤找到自己的父亲并进行交换。
void insert(int p)
{
h[++m]=p;
int j=m;
while((j>>1)>0 && h[j]>h[j>>1])
{
swap(h[j],h[j>>1]);
j>>=1;// j=j>>1; 相当于j=j/2;
}
return;
}
【删除】
假如我们要删除数组中第一个数,只要把第一个数和最后一个数进行交换就行了。这时,又会出现一些不符合堆的性质的情况出现:
如H[p]<H[ left(p) ]或H[p]<H[ right(p) ]的情况出现。那么,我们把它们交换不就可以了!但是,我们还有一个问题,假如
H[p]<H[ left(p) ]和
H[p]<H[ right(p) ]的情况都出现,那么应该交换那个呢?应该是较大的那一个。为什么呢?
![二叉堆 - 区庆亮 - oql 二叉堆 - 区庆亮 - oql](http://img2.ph.126.net/Ag1vS-BVwrgVGhfZnLRbSA==/6631358036773680230.png)
我们都知道,一个节点p的左孩子是p*2,右孩子是p*2+1,所以,我们可以从上往下进行比较并交换。
int Delete()//删除并输出最大值
{
int ans=h[1];
h[1]=h[m--];
int j=1,k;
while( j<<1<=m )
{
k=j<<1;
if(k<m && h[k]<h[k+1]) k++;//比较左孩子和右孩子的大小
if(h[k]<=h[j]) break;
swap(h[j],h[k]);//交换
j=k;
}
return ans;//最大值
}