【概述】
堆排序是一种不稳定的排序方法,其利用了堆的性质来进行排序,是选择排序的一种。
其基本思想是:将待排序的记录构成一个堆,然后不断将堆顶元素移走,并将剩余的记录调整成堆,直到堆空。
关于堆:点击这里
【实现过程】
堆排序的实现步骤为:
- 根据已有序列创建一个堆 heap[0..n-1]
- 堆首元素移除堆并加入至有序区,同时,将堆的尺寸缩小 1
- 将剩下的数据重新调整成堆,重复步骤 2,直到堆为空
【时空复杂度分析】
堆排序的运行时间主要消耗在初始建堆和重建堆时进行的反复筛选上,初始建堆需要 O(n) 的时间,第 i 次取堆顶记录重建堆需要 O(log i) 的时间,并且需要取 n-1 次堆顶记录,因此总的时间复杂度 O(nlogn)
由于序列的状态并不影响堆的建堆与筛选,因此无论是最好、最坏时间复杂度,还是平均时间复杂度,均为 O(nlogn)
对于空间复杂度来说,堆排序仅需要一个用来交换的暂存单元,故为 O(1)
【源程序】
int heap[N];
int size=0;
void put(int a[],int x){//heap[1]为堆顶
heap[++size]=x;//在堆尾加入元素
int now=size;//当前结点序号
while(now>1){
int next=now>>1;//该结点的父结点
if(heap[now]<=heap[next])//当前结点值小于其父结点值
break;
swap(heap[now],heap[next]);
now=next;
}
}
int get(){//heap[1]为堆顶
int now=1;//当前结点
int res=heap[1];要删除的结点
heap[1]=heap[size--];//堆长度-1
while(now*2<=size){
int next=now>>1;//当前结点的父结点
if(next<size&&heap[next+1]<heap[next])//比较左右孩子,指向较大者
next++;
if(heap[now]<=heap[next])//当前结点值小于其父结点值,结束
break;
swap(heap[now],heap[next]);
now=next;
}
return res;
}
void heapSort(int a[],int n){
for(int i=1;i<=n;i++)//初始建堆
put(a,a[i]);
for(int i=1;i<=n;i++){
int temp=get();//取堆顶元素并调整
a[i]=temp;//存储结果
}
}