MAX-HEAPIFY(A, i)
1 l ← LEFT(i)
2 r ← RIGHT(i)
3 if l ≤ heap-size[A] and A[l] > A[i]
4 then largest ← l
5 else largest ← i
6 if r ≤ heap-size[A] and A[r] > A[largest]
7 then largest ← r
8 if largest ≠ i
9 then exchange A[i] ↔ A[largest]
10 MAX-HEAPIFY(A, largest)
BUILD-MAX-HEAP(A)
1 heap-size[A] ← length[A]
2 for i ← ⌊length[A]/2⌋ downto 1
3 do MAX-HEAPIFY(A, i)
HEAPSORT(A)
1 BUILD-MAX-HEAP(A)
2 for i ← length[A] downto 2
3 do exchange A[1] ↔ A[i]
4 heap-size[A] ← heap-size[A] - 1
5 MAX-HEAPIFY(A, 1)
初始化:首先,对于第一轮迭代开始之前,最大堆已经建好,A[1]数组保存最大值。
保持:接下来,我们来考虑第二个性质:证明每一轮循环都能使循环不变式保持成立。在for循环2~5行的迭代开始时,子数组A[1..i]是一个包含了一个A[1..n]中的i个最小元素的最大堆;而子数组A[i+1..n]包含了已经排序的n-i个最大元素。
当i=k时,这时对应A[1]是剩余数组的最大值,先交换A[1]和A[k]中的值,那么交换后,A[1]很有可能不是剩余数组A[1..k-1]中的最大值,这时调用MAX-HEAPIFY(A, 1),因为在调用前,除了根节点外,都是符合最大堆的要求,调用MAX-HEAPIFY(A, 1)子过程可以保证在这种情况下把这个放于根节点的小元素调整到合适位置,而保持A[1..k-1]仍然是最大堆。(调整的部分符合最大堆规则,没有调整的部分也符合最大堆规则,因此可以保证)另外,A[1..k-1]是数组中最小的k-1个元素。而子数组A[k…n]包含了已排序的n-k+1个元素。这样就证明了每一轮循环都能使循环不变式保持成立。
终止:最后,分析一下循环结束时的情况。对于堆排序,当i等于1时,循环结束。在循环不变式中,那么意味着A[2..n]子数组包含了原来数组的最大的n-1个元素,且已经排序完成。而A[1]是A[1..n]中的最小元素,因此,整个数组就排序好了,这意味着算法是正确的。
BUILD-MAX-HEAP(A)的时间代价是O(n)
MAX-HEAPIFY(A, 1)的时间代价是O(lgn)
所以时间代价的上界是O(nlgn)