堆排序( heapsort )是指利用「堆」這種資料結構
所設計的一種排序演算法
。堆是一種資料結構,是乙個陣列。它可以被看成乙個近似的完全二叉樹,樹上的每乙個結點對應陣列中的乙個元素。除了最底層外,即葉子結點,該樹是完全充滿的,而且是從左到右填充。
最大堆的每個結點都要滿足堆的性質,此外還有其他的約束:堆中的最大元素存放在根結點中,並且在任一子樹中,該子樹所包含的所有結點的值都不大於該子樹根結點的值。
堆排序就是利用最大堆的性質來排序。大致步驟如下:
①建最大堆
②將根結點(最大元素)與最後乙個結點的元素互換,並將剩下的結點維護最大堆的性質。
③重複步驟②,直到將每個元素排完序。
下面就講解幾個重要過程:
維護最大堆的性質:maxheapify
傳入引數:待排序陣列、需要維護的下標、當前堆的大小。返回值:空
每次在傳入引數的下標、該下標的左、右孩子結點三者中選出最大的元素。如果最大元素是該下標,則滿足最大堆性質,結束。否則,需要將父親與最大的孩子交換位置,使得當前下標及其左右孩子滿足最大堆的性質。之後遞迴呼叫,使得整個子樹都滿足最大堆的性質。
特別需要注意,陣列的大小和堆的大小是不一樣的概念。堆的大小表示有多少個堆元素儲存在陣列中。在進行堆排序的過程中,每次需要把根結點元素與最後乙個元素交換,這樣堆的大小每次就會減一。而陣列大小是不會變的。也就是:
0 ≤ 堆的大小 ≤ 陣列的大小
建最大堆:buildmaxheap
傳入引數:待排序陣列、當前堆的大小。返回值:空
只需保證所有的非葉子結點滿足最大堆的性質即可。非葉子結點的下標為從0到堆大小 / 2(向下取整)。
堆排序:heapsort
傳入引數:待排序陣列、當前堆的大小。返回值:空
首先建堆,然後每次去除根結點元素(最大元素),然後維護最大堆的性質。如此迴圈,直到所有元素排序完畢。
實現**如下:
#include using namespace std;
typedef int elemtype;
int getleftchild( int i ) //返回左孩子下標。注:陣列從位置0開始
int getrightchild( int i ) //返回右孩子下標。注:陣列從位置0開始
void swap( elemtype *a, elemtype *b ) //交換兩個元素
/* 維護最大堆的性質。
* 引數:待排序陣列、需要維護的下標、當前堆的大小
* 返回值:空
*/void maxheapify( elemtype *a, int i, int num )
}/* 建最大堆
* 傳入引數:待排序陣列、當前堆的大小
* 返回值:空
*/void buildmaxheap( elemtype *a, int num )
/* 堆排序
* 待排序陣列、當前堆的大小
* 返回值:空
*/void heapsort( elemtype *a, int num )
}int main()
; heapsort( a, 10 );
for( int j=0; j<10; j++ )
cout << a[j] << " ";
cout << endl;
return 0;
}
時空複雜度:由於每次重新恢復堆的時間複雜度為o(logn),共n - 1次重新恢復堆操作,再加上前面建立堆時n / 2次向下調整,每次調整時間複雜度也為o(logn)。二次操作時間相加還是o(n * logn)。故堆排序的時間複雜度為o(n * logn)。
由於建初始堆所需的比較次數較多,所以堆排序不適宜於記錄數較少的檔案。
堆排序是就地排序,輔助空間為o(1), 它是不穩定的排序方法。
演算法導論 6 堆排序
堆的分類 最大堆性質 高度 對於堆的一些基本操作 偽 描述 實現 max heapify python實現 123 4567 891011 1213 def max heapify i print max heapify i l left i r right i if l heap size and...
《演算法導論》學習分享 6 堆排序
堆排序也是一種時間複雜度為o n lg n omicron n lg n o nlgn 的排序演算法,但是與歸併排序不同的是堆排序是一種原址排序,也就是說排序過程只是交換資料的位置。堆是乙個陣列,儲存乙個近似完全二叉樹,樹上的每個結點對應陣列中的乙個元素,陣列第乙個元素儲存根節點,第i個元素的左孩子...
演算法導論讀書筆記(6)堆排序
複雜度o nlgn 原址排序 集插入排序和歸併排序兩者的優點 計算給定節點下標i的父,左孩子,右孩子的下標 parent i return i 2 left i return 2i right i return 2i 1 最大堆 堆中最大元素存放在根結點 最小堆 堆中最小元素存放在根結點 從a i ...