關於堆排序的介紹主要引自一博文,比較詳細的例子可參考另外一博文。html
動畫演示能夠參考一網頁。git
關於二叉堆,有一博文二叉堆(一)之 圖文解析寫的很清晰詳細,很值得參考。github
堆給人的感受是一個二叉樹,可是其本質是一種數組對象,由於對堆進行操做的時候將堆視爲一顆徹底二叉樹,樹中每一個節點與數組中的存放該節點值的那個元素對應。因此堆又稱爲二叉堆,堆與徹底二叉樹的對應關係以下圖所示:算法
一般給定節點i,能夠根據其在數組中的位置求出該節點的父親節點、左右孩子節點,這三個過程通常採用宏或者內聯函數實現。書(《算法導論》)上介紹的時候,數組的下標是從1開始的,因此可獲得:PARENT(i)=i/2 LEFT(i) = 2*i RIGHT(i) = 2*i+1。數組
注:我的在程序實現的時候默認是從0開始的,所以left = 2*i+1, right = 2*i+2。函數
根據節點數值知足的條件,能夠將分爲最大堆和最小堆。最大堆的特性是:除了根節點之外的每一個節點i,有A[PARENT(i)] >= A[i],最小堆的特性是:除了根節點之外的每一個節點i,有A[PARENT(i)] >=A[i]。動畫
把堆當作一個棵樹,有以下的特性:ui
1)含有n個元素的堆的高度是lgn。this
2)當用數組表示存儲了n個元素的堆時,葉子節點的下標是n/2+1,n/2+2,……,n。spa
3)在最大堆中,最大元素該子樹的根上;在最小堆中,最小元素在該子樹的根上。
堆個關鍵操做過程是如何保持堆的特有性質,給定一個節點i,要保證以i爲根的子樹知足堆性質。書中以最大堆做爲例子進行講解,並給出了遞歸形式的保持最大堆性的操做過程MAX-HEAPIFY(注:個人程序中名爲adjustHeap)。先從看一個例子,操做過程以下圖所示:
從圖中能夠看出,在節點i=2時,不知足最大堆的要求,須要進行調整,選擇節點2的左右孩子中最大一個進行交換,而後檢查交換後的節點i=4是否知足最大堆的要求,從圖看出不知足,接着進行調整,直到沒有交換爲止。
創建最大堆的過程是自底向上地調用最大堆調整程序將一個數組A[1.....N]變成一個最大堆。將數組視爲一顆徹底二叉樹,從其最後一個非葉子節點(n/2)開始調整。調整過程以下圖所示:
堆排序算法過程爲:先調用建立堆函數將輸入數組A[1...n]形成一個最大堆,使得最大的值存放在數組第一個位置A[1],而後用數組最後一個位置元素與第一個位置進行交換,並將堆的大小減小1,並調用最大堆調整函數從第一個位置調整最大堆。給出堆數組A={4,1,3,16,9,10,14,8,7}進行堆排序簡單的過程以下:
(1)建立最大堆,數組第一個元素最大,執行後結果下圖:
(2)進行循環,從length(A)到1,並不斷的調整最大堆,給出一個簡單過程以下:
1 void HeapSort::sort() 2 { 3 buildHeap(); 4 for (int i = 0; i < len; i++) 5 { 6 int hLen = len - i; 7 // It is been done in buildHeap() when i = 0 8 if (i != 0) 9 adjustHeap(0, hLen); 10 exchange(0, hLen - 1); 11 } 12 } 13 14 void HeapSort::buildHeap() 15 { 16 int n = 1; 17 while (len > pow(2.0, n) - 1) 18 { 19 adjustHeap(0, len); 20 n++; 21 } 22 } 23 24 void HeapSort::adjustHeap(int start, int hLen) 25 { 26 if (start >= hLen - 1) return; 27 28 int left = 2 * start + 1; 29 int right = 2 * start + 2; 30 31 // This also means left < hLen and 32 // arr[left] and arr[right] exist. 33 if (right < hLen) 34 { 35 // This means arr[start] is smaller than one of its child, so we just 36 // need to find a larger child to replace it. 37 if (arr[start] < arr[left] || arr[start] < arr[right]) 38 { 39 if (arr[left] >= arr[right]) 40 { 41 exchange(start, left); 42 } 43 else 44 { 45 exchange(start, right); 46 } 47 } 48 } 49 // This means left < hLen <= right and arr[right] does not exist. 50 else if (left < hLen) 51 { 52 if (arr[start] < arr[left]) 53 { 54 exchange(start, left); 55 } 56 } 57 // This means hLen <= left, arr[left] does not exist and arr[start] has no child. 58 // Actually, 'else' branch is not necessary as 'if (start >= hLen - 1) return;' 59 // at the beginning has ensured this. 60 else 61 { 62 return; 63 } 64 65 adjustHeap(start + 1, hLen); 66 adjustHeap(start + 2, hLen); 67 }
完整程序請見Github.