首先是堆的定义:堆就是完全二叉树,从头到尾,头最小
下面是关于堆的代码实现:
首先是在数组中实现堆:
for(int i=n/2;i;i--)
down(i);
// O(n) 建堆
//down
down的意思是在一个头如果小于他的两个儿子那么进行交换,所以是下降的意思,
那么代码的意思是从二分之一的数开始进行对每个点的down操作,那么就遍历到每个数了。
每三个点成一个down的三点。所以只需要从n/2开始到 i=0 时即可,全部形成了头比两个儿子小的堆了。
down的代码:
void down(int u)
{
int t=u;
if(h[u]>h[u*2]&&u*2<=n)t=u*2;
if(h[u]>h[u*2+1]&&u*2+1<=n)t=u*2+1;
if(u!=t)
{
swap(h[u],h[t]);
down(t);
}
}
然后就是up操作了,如果当前点小于他的两个父亲节点那么进行交换操作:
void up(int u)
{
while(h[u/2] >= h[u] && u/2)
{
swap(h[u/2],h[u]);
u>>=1;// 等价于u/2;
}
}
最基本的操作还有,交换,因为在进行堆的操作时,还涉及到了堆的维护,由此
heap_swap();
// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
void heap_swap(int i,int j)// i,j分别表示他们所在堆中的位置
{
swap(ph[hp[i]],ph[hp[j]]); //先交换所插入的点所在堆中的位置。
swap(hp[i],hp[j]); //再交换记录两点插的顺序。
swap(h[i],h[j]); //最后交换两点的值。
}
第一个和第二个的swap位置不能够交换,第三个的位置可以随便。
再维护堆的时候还有很多操作:ex 删除某个点,直接swap再size–;再down就行了
再或者改变
相关如上,操作不难,最重要的是函数的理解和运用,还有对堆的深刻理解。