堆排序:堆每一次DeleteMin的时间复杂度是O(logn),这看起很不错,因为n次出堆也只需要O(nlogn)次。那我们是否可以每次出最小树,这样将数组排序呢?
当然可以!我们这就来实现一下!
如果忘记DeleteMin的实现,我们不妨再重新复习一下。队列那些事儿
int DeleteMin(priority_queue pq){
if(pq.empty()) error();
int min=pq.elements[1];
int lastone=pq.elements[pq.size()--];
int child;
for(int i=1;i*2<q.size();i=child){
child=i*2;
if(child!=pq.size()&&pq.elements[child]>pq.elements[child+1])
child++;
if(pq.elements[child]<lastone)
pq.elements[i]=pq.elements[child];
else
break;
}
pq.elements[i]=lastone;
return min;
}
堆排序算法
如果我们每次进行DeleteMin操作,将min存储到一个数组中,这样n次之后就会得到一个排好序的结果。这样的坏处是要求一个O(n)的额外数组,这很明显不如快排。
我们这里有一个小技巧,可以去掉这个额外数组。
每次将最顶端的数字和最末端的数字交换,pq.size()- -,然后就可以利用原本的数组来存储这个结果(虽然是逆序的)
这个算法稍微复杂了一些,这次的数组更“正式”一些(回想一下,deletemin是一个内部结构),下标0处包含着数据。
//i:从i处开始下滤
#define leftchild (i*2+1)
void perdown(int A[],int i,int N){
int child;
int tmp;
for(tmp=A[i];i*2<N-1;i=child){
child=leftchild(i);
if(child+1<q.size()&&A[child+1]<A[child])
child++;
if(tmp<A[child])
A[i]=A[child];
else
break;
}
A[i]=tmp;
}
也许这段代码比较难以理解,但是现在综合Deletemin就比较简单了,这个过程其实是在给A[i]寻找一个合适的位置
堆排序的正式过程
void HeapSort(int *A,int N){
for(int i=N/2;i>=0:i--)//BuildHeap
perdown(A,i,N);
for(int i=N-1;i>0;i--){
swap(&A[i],&A[0]);//DeleteMin
perdown(A,0,N);
}
}