堆用數組來實現,但是其中元素有順序,滿足最大(小)堆的性質,如a[i]>a[i+1]&&a[i]>a[i+2],堆排序的思想是對於一個無序的數組,首先建堆,然後將第一個元素與最後一個元素交換位置,這樣因為第一個元素是最大(小)值,就可以取出來了,再對其餘N-1個元素進行堆得整理,代價為logn,然後再次取出第一個元素,以此類推,總的排序代價為O(N*logN)。注意建堆的代價為O(N)。
C++的實現代碼如下:
/*堆排序演算法:最大時間複雜度為O(N*logN),即每次交換到堆頂的元素都是最小的,這樣堆整理的操作時間最長堆排序與選擇排序演算法相似,只不過選擇排序每次選出一個當前最大元素時都需要比較n-1次(n一直在遞減),即他沒有記錄其他元素的大小關係,這樣導致每次都需要進行很多次重複比較,而堆排序則把其他元素放在堆中堆是有序的,這樣減少了每次選出最大元素的比較次數,因為其他元素的大小關係已經確定,不用再比較*/#include <iostream>#include <algorithm>using namespace std;void heapAdjust(int *a, int i, int size);void heapSort(int *a, int size);void buileHeap(int *a, int size);int main(){ int i, size; int a[100]; while(scanf("%d", &size)==1&&size>0) { cout<<"size is "<<size<<endl; for(i=1;i<=size;i++) //節點序號從1開始,方便後續的堆操作 { cin>>a[i]; } cout<<"input over"<<endl; buileHeap(a, size); heapSort(a, size); for(i=1;i<=size;i++) cout<<a[i]<<","; cout<<endl; } return 0;}
/*調整堆的函數*/void heapAdjust(int *a, int i, int size){ int leftchild=2*i; int rightchild=2*i+1; int max=i; if(i<=size/2) {//cout<<"i="<<i<<endl; if(leftchild<=size&&a[leftchild]>a[max]) //注意判斷leftchild和rightchild的範圍是否超過了size max=leftchild; if(rightchild<=size&&a[rightchild]>a[max]) max=rightchild; if(max!=i) { swap(a[i], a[max]); heapAdjust(a, max, size); //只有max不等於i時才遞迴調用,否則會死迴圈 } } return;}
/*堆排序函數*/void heapSort(int *a, int size){ buileHeap(a, size); int i; for(i=size;i>1;i--) { swap(a[1], a[i]); //每次把最大元素交換到最後的位置 heapAdjust(a, 1, (i-1)); //注意此處的第三個參數應該是當前堆的長度減1 } return;}
/*建堆函數*/void buileHeap(int *a, int size){ int i; for(i=size/2;i>0;i--) //非分葉節點的序號最大為size/2,注意節點序號從1開始,這樣方便。 { heapAdjust(a, i, size); }}