堆算法
堆的主要算法:
维护堆的性质:MAX-HEAPIFY:O(lgn)
算法思想:在程序的每一步中,从A[i]、A[LEFT(i)]和A[RIGHT(i)]中选出最大的,并将其下标存储在largest中。如果A[i]是最大的,那么以i为根
结点的子树已经是最大堆,程序结束。否则,最大元素是i的某个孩子结点,则交换A[i]和A[largest]的值。从而使i及其孩子都满足最大堆的性质。
在交换后,下标为largest结点的值是原来的A[i],于是以该结点为根的子树又有可能会违反最大堆的性质。因此,需要对该子树递归调用MAX_HEAPIFY
伪码如下:
MAX-HEAPIFY(A,i):
1 l = LEFT(i) 2 r = RIGHT(i) 3 if l <= A.heap-size and A[l] > a[i] 4 largest = l 5 else largest = i 6 if r <= A.heap-size and A[r] > A[largest] 7 largest = r 8 if largest != i 9 exchange A[i] with A[largest] 10 MAX-HEAPIFY(A, largest)
算法导论上有证明:MAX-HEAPIFY的时间复杂度为O(h)
将该算法优化为非递归的形式,伪码如下:
MAX-HEAPIFY(A,i)
1 while i <= A.heap-size 2 l = LEFT(i) 3 r = RIGHT(i) 4 if l <= A.heap-size and A[l] > A[i] 5 largest = l 6 else 7 largest = i 8 if r <= A.heap-size and A[r] > A[largest] 9 largest = r 10 if largest != i 11 exchange A[i] with A[largest] // 注意这里i的值也更新为largest了 12 else // 已经满足最大堆性质 13 break
建堆:O(n)
我们可以用自底而上的方法利用过程MAX-HEAPIFY把一个大小为n = A.length的数组A[1...n]转换为最大堆。
BUILD-MAX-HEAP(A)
1 A.heap-size = A.length 2 for i = A.length / 2 downto 1 3 MAX-HEAPIFY(A,i)
堆排序:O(nlgn)
初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组A[1...n]建成最大堆,其中n=A.length。因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]进行互换,
我们可以让该元素放到正确的位置。这时候,如果我们从堆中去掉结点n(这一操作可以通过减少A.heap-size的值来实现),剩余的结点中,原来根的孩子结点
仍然是最大堆,而新的根结点可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的是调用MAX-HEAPIFY(A,1),从而在A[1...n-1]上构造一个新的最大堆。
堆排序算法会不断重复这一过程,直到堆的大小从n-1降到2。
HEAPSORT(A)
1 BUILD-MAX-HEAP(A) 2 for i = A.length downto 2 3 exchange A[1] with A[i] 4 A.heap-size = A.heap-size - 1 5 MAX-HEAPIFY(A,1)
堆算法的应用:优先队列
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中的每个元素都有一个相关的值,成为“关键字(key)”。一个最大优先队列支持以下操作:
INSERT(S,x):把元素x插入集合S中。
MAXIMUM(S):返回S中具有最大键字的元素。
EXTRACT-MAX(S):去掉并返回S中的具有最大键字的元素。
INCREASE-KEY(S,x,k):将元素x的关键字值增加到k,这里假设k的值不小于x的原关键字值。
HEAP-MAXIMUM(A):O(1)
1 return A[1]
HEAP-EXTRACT-MAX(A):O(lgn)
1 if A.heap-size < 1 2 error"heap underflow" 3 max = A[1] 4 A[1] = A[A.heap-size] 5 A.heap-size = A.heap-size - 1 6 MAX-HEAPIFY(A,1) 7 return max
HEAP-INCREASE-KEY(A,i,key):O(lgn)
1 if key < A[i] 2 error"new key is smaller than current key" 3 A[i] = key 4 while i > 1 and A[PARENT(i)] < A[i] 5 exchange A[i] with A[PARENT(i)] 6 i = PARENT(i)
MAX-HEAP-INSERT(A,key):O(lgn)
1 A.heap-size = A.heap-size + 1 2 A[A.heap-size] = -00 3 HEAP-INCRESE-KEY(A,A.heap-size,key)
总之,在一个包含n个元素的堆中,所有优先队列的操作都可以在O(lgn)时间内完成