性质
二叉堆是完全二叉树,所以,它符合完全二叉树的性质,可以参阅http://blog.csdn.net/gykimo/article/details/8594297。
另外二叉堆(大堆)要求每个结点的值大于它所有子孙结点的值,也就是最大值就是根结点。
保持最大堆的性质
也就是判断某个结点的值是否大于它的两个孩子的大小,如果不是,则不符合最大堆性质,需要该结点和两个孩子中的较大的结点交换;交换到新位置后,还要递归判断是否符合最大堆性质。代码参考代码部分的heapify函数。
建堆
参考代码部分的build()函数。
问题一:为什么只需要处理总结点数的一半就可以生成最大堆
因为,叶子不需要执行最大堆性质,因为叶子没有孩子,自然叶子就是最大的,即符合最大堆性质,所以只需要对内结点执行最大堆性质即可。根据完全二叉树的性质得出,内结点的数量最多是总结点数的一半,所以只需要执行总结点数的一半的最大堆性质操作就可以得到最大堆。
问题二:时间复杂度
乍一看应该是O(nlogn),其实经过严格计算,复杂度为O(n),也就是可以在线性时间内完成最大堆的建立。
排序
最大堆的最大值是根结点,所以可以在O(1)时间内取出最大值,但是取出最大值后,需要一个新的结点来顶替根结点,这里一个巧妙的办法是将最后一个元素顶替根结点,然后进行保持最大堆性质操作。代码参考代码部分的sort函数。
代码
/*
*
* Introduction : heap sort
* Author : Gykimo
* Date : 20130104
*
*/
#ifndef _LIBS_HEAP_SORT_H
#define _LIBS_HEAP_SORT_H
#include <stdio.h>
class heapsort{
public:
heapsort()
:mRoot(NULL),
mIsMax(true),
mSize(0){}
heapsort(int * nodeList, int len, bool isMax);
virtual ~heapsort(){}
void sort();
protected:
int * mRoot;
bool mIsMax; /*max heap or min heap*/
int mSize;
void heapify(int i);
void build();
inline int getParent(int i){ return (i-1)>>1; }
inline int getLeft(int i){ return (i<<1) + 1; }
inline int getRight(int i){ return (i<<1) + 2; }
inline int getLast(){return mSize - 1;}
};
heapsort::heapsort(int * nodeList, int len, bool isMax)
:mRoot(nodeList),
mIsMax(isMax),
mSize(len){
build();
}
void heapsort::build(){
for(int i = getParent(getLast()); i>=0; i--){
heapify(i);
}
}
void heapsort::heapify(int i){
int tmp;
if(mIsMax){
int largest;
if((getLast() >= getLeft(i)) && mRoot[i] < mRoot[getLeft(i)])
largest = getLeft(i);
else
largest = i;
if((getLast() >= getRight(i)) && mRoot[largest] < mRoot[getRight(i)])
largest = getRight(i);
if(largest != i){
tmp = mRoot[i];
mRoot[i] = mRoot[largest];
mRoot[largest] = tmp;
heapify(largest);
}
}else{
int smallest;
if((getLast() >= getLeft(i)) && mRoot[i] > mRoot[getLeft(i)])
smallest = getLeft(i);
else
smallest = i;
if((getLast() >= getRight(i)) && mRoot[smallest] > mRoot[getRight(i)])
smallest = getRight(i);
if(smallest != i){
tmp = mRoot[i];
mRoot[i] = mRoot[smallest];
mRoot[smallest] = tmp;
heapify(smallest);
}
}
}
void heapsort::sort(){
int tmp;
for(int i=getLast(); i>0; i--){
tmp = mRoot[i];
mRoot[i] = mRoot[0];
printf("%d ", mRoot[i]);
mRoot[0] = tmp;
mSize--;
heapify(0);
}
printf("%d\n", mRoot[0]);
}
#endif