编程珠玑column14 heaps

堆的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)

因为叶子节点处已经是堆,不用考虑叶子节点


有一道百度笔试题与堆相关

一个最小堆,也是完全二叉树,用按层遍历数组表示。
  1.  求节点a[n]的子节点的访问方式
  2.  插入一节点的程序void add_element(int *a,int size,int val);
  3.  删除最小节点的程序。
子节点下标为2*n+1,2*n+2
前n个节点,每个节点有两个子节点,相当于2n个节点
证明:

假设父节点在i层,从0层开始,则父节点与之前的所有节点数为
2^0+2^1+2^2+...2^i=2^(i+1)-1
假设父节点为i层的第j个节点
前i层所有节点数(不含i层)

2^0+2^1+2^2+...2^(i-1)=2^i-1
k=2^i-1+j-1=2^i+j-2(因为位置从0开始)
i层上父节点之前的节点每个有2个子节点,所以
子节点之前的节点数2^(i+1)-1+(j-1)*2=2^(i+1)+2j-3
子节点所在的节点=2^(i+1)+2j-3+1-1=2*k+1
或2^(i+1)+2j-3+2-1=2*k+2



插入一节点插入到数列最后,调整堆即可
把该节点调整到堆的合适位置,使堆仍维持最小堆的性质即可

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;
}


删除节点的思想为把a[0]赋值成堆末尾的元素,修改size大小,然后从堆顶向下调整堆
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;
}






你可能感兴趣的:(编程珠玑column14 heaps)