這裏先簡單說下最大堆的基本性質:數組
瞭解以上基本性質以後,就能夠先看一下如何對一個序列作最大堆的初始化。3d
思路:過程就像冒泡同樣,從最序號最大的父節點開始,查看是否知足最大堆,若是不知足,則調整(調整以後,還要查看被調整的節點是否依然知足最大堆性質,若是不知足,則須要往下遍歷調整,這部分在後面的舉例中會有說明),若是知足,則繼續查看前一個父節點是否知足,直接最終的0節點。code
例如:這裏有個數組:x[] = {2 5 3 9 7 1 6},則對應樹爲:
blog
該序列長度爲7,最大下標爲6,則最大的父節點下標就是: (6 - 1)/ 2 是2(基本性質第三條),對應的數值是3,
他的左孩子是1,右孩子是6,右孩子比父節點大,因此應該調整一下這兩個節點,獲得:
排序
該節點調整完以後,再查看前一個父節點,下標爲1,對應的數值爲5,
他的左孩子是9,右孩子是7,不知足,因此父節點應該與左孩子進行交換,獲得:
string
繼續往前,再前面一個父節點下標爲0,數值爲2,左孩子是9,右孩子是6,不知足最大堆,父節點與左孩子交換,獲得:
io
交換以前,左孩子爲9,如今左孩子爲2,致使這個左孩子不知足最大堆性質,由於這個左孩子的左孩子大於左孩子,因此,這裏就出現了上面括號中所說的:調整完以後,還要查看被調整的節點是否依然知足最大堆的性質。
這裏還要對調整以後的節點繼續調整:
class
至此,一個最大堆就初始化完成了!二叉樹
其實,明白了最大堆怎麼構造出來的以後,堆排序就很容易了。
想想,最大堆構造出來以後,其實就直接獲得了最大值:x[0],
若是把 x[0] 與最後一個數字交換一下,而後對剩下的數字從新按以前的方法構造一下,不就找到了第二大的數字了嗎?
此時第二大的數字就是x[0],把它與剛剛參加排序的最後的一個數字交換一下,而後再對剩下的數字排序一下,就能夠獲得第三大的數字,
這麼一直循環,就能夠把當前數組排序完成了。
接着剛剛的那個例題,先把9與參與排序的最後一個數字對換,獲得:
循環
此時參與排序的,就只有:3,7,6,5,2,1。
由於x[0]被調整了,因此要查看x[0]是否依然最大堆性質,顯然是不知足的,因此繼續調整x[0],獲得:
x[0]與x[1]互換以後,致使被調整的x[1]又不知足最大堆,那就再調整一下:
如今整個樹都知足最大堆了,也就獲得瞭如今參與排序的最大值x[0]爲7,
因此,x[0]與當前參與排序的最後一位交換,獲得:
此時參與排序的,只有:1,5,6,3,2。
按照上面步驟再次循環,這裏就不寫了,直接放圖:
上代碼:
#include <stdio.h> #include <string.h> #include <stdlib.h> void swap(int *array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; return; } // 對當前父節點進行排序 // 查看該父節點是否知足最大堆,若是不知足則調整子節點 void sort (int *array, int father, int len) { for (int lchild =father*2+1; lchild<len; lchild=father*2+1) { int k = lchild; // 先用k指向左孩子 int rchild = lchild + 1; if ((rchild < len) && (array[rchild] > array[lchild])) { k = rchild; // 若是有右孩子,且右孩子比左孩子還大,則更新k } // 這裏的k,指向了左右孩子中較大的那個 if (array[k] > array[father]) { swap(array, k, father); // 交換父親和孩子的數值 father = k; // 這裏就是查看被調整以後的節點k,是否依然知足最大堆 } else { break; // 當前節點不須要被調整 } } return; } void print(int *array, int len) { for (int i=0; i<len; i++) { printf("%d ", array[i]); } printf("\n"); } int main(void) { int x[] = {2,5,3,9,7,1,6}; int len = sizeof(x)/sizeof(int); print(x, len); // 先輸出原始序列 // 最大子節點下標爲len-1,因此它的父節點是 (len-1-1) / 2 for (int i = (len - 2)/2; i>=0; i--) { sort(x, i, len); } print(x, len); // 輸出初始化以後的最大堆 for (int i=(len-1); i>0; i--) { swap(x, 0, i); // 把最大的一個值放到末尾,而後對剩餘的數組進行排序 sort(x, 0, i); } print(x, len); // 輸出排序以後的序列 return 0; } 最終輸出爲: 2 5 3 9 7 1 6 9 7 6 5 2 1 3 1 2 3 5 6 7 9