堆的siftdown操作
假设x[1..n]的序列已经是一个堆,现在修改x[1]的值,然后调整这个序列使维持堆的性质
初始化所以i为1,直到i没有子节点或者子节点的值均大于i所在的节点的值为止。
把c设置成节点i的子节点中值较小的节点索引
c=2*i
if(c+1<=n)
if(x[c+1]<x[c])
c++
顺便看了下堆排序:
堆排序建堆的时候是从所有节点的一半处开始建堆。
堆中叶节点的个数大于等于所有节点数的一半(1/2)
所以建堆时都从所有节点的一半处开始建,因为所有节点数为奇数时,叶节点数比非叶子节点数多1.
所有节点数为偶数时,叶子节点数与非叶子节点数相等。
证明:
假设该堆的层数为i
情况(1):若第i层全部为叶节点
则第1层到第i-1层全部为非叶子节。
非叶子节点数为2^0+2^1+..2^(i-2)=2^(i-1)-1
第i层节点数至少是第i-1层的节点数的2倍减1
即二叉树中叶节点个数>=2^(i-2)*2-1=2^(i-1)-1
且二叉树中叶节点个数<=2^(i-2)*2=2^(i-1)
此情况下成立
情况(2)若第i-1层部分为叶子节点,部分为非叶子节点。
设i-1层非叶子节点数为x,则该层叶子节点数为2^(i-2)-x
第i层叶子节点数至少是第i-1层非叶子节点数的2倍减1
即i层叶子节点数>=2x-1
且第i层叶子节点数<=2x(若每个内部节点都有两个子节点)
总叶子节点数>=2x-1+2^(i-2)-x=2^(i-2)+x-1
总叶子节点数<=2x+2^(i-2)-x=2^(i-2)+x
非叶子节点数为=2^0+2^1+..+2^(i-3)+x=2^(i-2)+x-1
结论也成立
14.3
介绍了用堆实现最小优先级队列的代码
最小优先级队列实现排序的时候相对堆排序要多维护优先级队列的数据结构
14.6
modify siftdown
这里只要修改原来版本的i=1用l来代替,n用u来代替即可。
至于用该函数来实现siftdown。其实只要从一半节点处siftdown即可。
即for(i=n/2;i>=1;i--)
siftdown(i,n)
因为叶子节点处已经是堆,不用考虑叶子节点
有一道百度笔试题与堆相关
void add_element(int *a,int size,int val){ a[size]=val; //parent node int p=size/2-1; //current position of val int c = size; while(p>=0){ if(a[p]<a[c]) break; else{ //sift up a[c]=a[p]; c=p; p=(p-1)/2; } } a[c] = val; }
void del(int *a,int size){ a[0]=a[size-1]; int val=a[0]; size--; int p=0; //child node with smaller value int c=2*p+1; while(c<=size-1){ if(c<size-1&&a[c]>a[c+1]){ // c is the lesser child of parent c++; } if(a[p]<=a[c]) break; else{ a[p]=a[c]; p=c; c=2*p+1; } } a[p]= val; }