堆算法

堆的主要算法:

维护堆的性质: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)时间内完成

 

posted @ 2019-05-25 17:15  Shiko  阅读(783)  评论(0编辑  收藏  举报