一,堆的性质
1.顶部总是保存着最小或者最大的元素
2.有弹出操作,插入操作,合并操作,并且无论进行什么操作,都保持堆的性质1不变。
二,堆的实现
我用的是数组来实现隐式二叉堆,数组实现的二叉堆主要的是二叉堆的节点到数组下标的映射。比如堆中的第 i 个节点,对应数组下标也为i,然后通过下标的映射来找父节点,左儿子,右儿子。父节点的下标为i/2,左儿子为2i,右儿子为2i+1。
三,堆最重要的一个性质是能够保持性质不变,也就是说我们需要维护堆的性质,对于用数组表示的二叉堆,给定任意索引 i 的节点,我们检查它的两个子节点,判断是否符合堆的性质,不符合就交换,使它符合堆的性质,这种维护的算法,是基于两个子树是合法堆的条件的。
//最小堆的维护算法示例
void heapify(int *A, int i ,int size){//A为数组,i为节点,size为数组长度
int left,right,smallest_index;//左子,右子,最小值点的下标
while ( 1 ) {//迭代到符合堆的性质
left = 2i;
right = 2i+1;
smalles_index = i;
//两个if判断,找出3个节点中值最小的节点的下标
if(left < size && A[i] > A[left])
smallest_index = left;
if(right < size && A[smallest_index] > A[right])
smallest_index = right;
//如果父节点不是值最小的,就将值最小的节点的值与父节点交换
if(smallest_index != i){
swap(A[i],A[smallest_index]);
i = smallest_index//将i迭代为发生交换的子节点,以便下次循环使用
}
else return;//如果父节点是最小节点,说明堆的性质正确
}
}
如果是维护最大堆的性质,只要将数值比较那一部分修改一下就可以了。
三,堆的构造
我们可以用heapify算法从任意数组构造堆,相当于维护一个完全无序的堆,这样我们就不能自顶向下来修正堆的构造了,而要从下至上修正。由于堆的叶子节点没有子节点,所以它们是视为符合堆的性质的,所以从最后一个有分支的节点开始修正,这个节点是最后一个节点的父节点,所以索引为n/2,n为数组长度。
这样分析,我们可以写出构造堆的算法如下:
void build-heap(int *A,int size){//A为数组,size为数组长度
int i;
for(i = size/2;i > 0;i--)
heapify(A,i,size);
return;
}
四,堆的基本操作
堆的通用定义通常要求我们提供一些基本操作,使用户可以获取或者修改数据:
int top(int *A){
return A[0];
}
2.弹出堆顶元素
我们需要在移除顶部元素后,通过执行heapify算法来维护堆的性质。最好的办法使记录下数组的首个元素,然后与最后一个元素交换,然后用heapify维护堆的性质。
int pop(int *A,int size){
swap(A[0],A[--size]);
heapify(A,0,size);//注意此时的size已经是减一了的
return A[++size];
int* top-k(int *A,int k, int size){//返回一个指针
int *p;
p=(int*)malloc(k*sizeof(int));
for(int i = 0;i < k;i++)
p[i]=pop(A,size);
return p;
4.插入
对于插入操作,我们可以直接将元素插到数组末尾,然后自底向上恢复堆的性质
void insert(int *A,int size,int k){
A[size++]=k;
int i;
for(i = size/2;i >= 0;i--)
heapify(A,i,size);
return;
int* heap-sort(int *A,int size){//A为待排序数组,size是数组长度
int *p;
p=(int *)malloc(size*sizeof(int));
//先构造堆出来
buile-heap(A,size);
//然后将顶部元素pop出来储存到另一数组中
for(int i = 0;i<size;i++)
p[i]=pop(A,size);
return p;
}
这个算法需要额外的空间复杂度O(n),Robert W.Floyd给出了一个原地排序,无需创建额外数组的方法:
void great-heap-sort(int *A,int size){
build-heap(A,size);
while(size>1){
swap(A[0],A[--size]);
heapify(A,size,0);
}
}