堆排序的时间复杂度为o(nlogn)不需要额外空间
堆可以看成一个存储在数组中的近似完全二叉树结构。
下标为(0…n)父节点下标为p则左孩子下标为2p+1
,右孩子下标为2p+2。其中在最大(小)堆中,父节点比两个孩子节点大(小)。在这里仅讨论最大堆。
对堆的操作:
void MaxHeapify(int *numSequence ,int i,int lenth);//最大堆的维护
void Build_MaxHeap(int *numSequence,int lenth);//建造最大堆
void Heap_Insert(int *numSequence,int *lenth,int x);//向最大堆中插入元素
void Heap_Sort(int *numSequence,int lenth);//堆排序
int Heap_Pop(int *numSequence,int *lenth);//弹出
int Maximum(int *numSequence)//返回最大值
堆的维护:维护某一个节点,使以它以及它的子节点为根节点的堆都为最大堆,递归调用自己(前提:以子节点为跟节点的堆都为最大堆)
建造最大堆:从后往前遍历每个非叶节点,对其调用堆维护。
堆的插入:将要插入的元素放在序列的尾部,再不断与父节点比较,若大于父节点,则与父节点交换,否则已经是一个最大堆。
堆排序:首先建造一个最大堆,然后不断将下表为0的元素与序列最后一个元素交换位置,堆的长度减一,再对下标为0的节点调用堆的维护。重复此操作,直到堆的长度小于等于1.
弹出:弹出堆的根节点的元素,lenth-1,并将最后的元素移到跟节点,调用堆的维护。
这里是C语言实现:
void MaxHeapify(int *numSequence ,int i,int lenth){//维护堆
int left ,right,maxchild;
if(lenth/2-1<i)return;//若为叶节点直接返回
else{
left=2*i+1,right=2*i+2,maxchild=left;
if(right<lenth)maxchild=cmp(numSequence[right],numSequence[left])>0?right:left;
if(cmp(numSequence[i],numSequence[maxchild])<0){
swap(i,maxchild,numSequence);
MaxHeapify(numSequence,maxchild,lenth);
}
}
}
void Build_MaxHeap(int *numSequence,int lenth){
int i;
for(i=lenth/2-1;i>=0;i--){
MaxHeapify(numSequence,i,lenth);
}
}
void Heap_Insert(int *numSequence,int *lenth,int x){
numSequence[(*lenth)++]=x;
int i,parent,child,tmp;
child=*lenth-1;
parent=child/2-1;
while(child!=0){
if(cmp(numSequence[child],numSequence[parent])>0){
swap(child,parent,numSequence);
child=parent,parent=child/2-1;
}
else break;
}
}
void Heap_Sort(int *numSequence,int lenth){
Build_MaxHeap(numSequence,lenth);
for(;lenth>1;){
swap(0,lenth-1,numSequence);
MaxHeapify(numSequence,0,--lenth);
}
}
int Heap_Pop(int *numSequence,int *lenth){
swap(0,*lenth-1,numSequence);
*lenth--;
MaxHeapify(numSequence,0,*lenth);
}
int Maximum(int *numSequence){
return numSequence[0];
}