堆排序综合了插入排序的原址(只需要常量额外空间)和归并排序时间复杂度为O(nlg(n))的有点的一种排序方法
6.1 堆
堆是一个数组,可以被看成一个近似的完全二叉树(即用利用二叉树的数学特性,使用数组实现的一种二叉树),包含有length和size连个属性,index < size的数据有效。二叉树的下标index的左右子节点位置分别为2i,2i+1,根节点为floor(i/2):
def PARENT(i):
return (i-1) // 2
def LEFT(i):
return i*2 + 1
def RIGHT(i):
return i*2 + 2
根节点的值不小于子节点的值称为最大堆,根节点的值不大于子节点的值称为最小堆。二叉树的高度为lg(n),n为元素个数,故而一些基本操作与树的高度成正比,时间复杂度为O(lg(n))。基本过程有:
6.2维护堆的性质
若最大堆的某个元素破坏了,最大堆的性质(即父节点小于子节点)需要将父节点,左右节点中的最大值放置到父节点的位置,置换之后在递归的调用MAX_HEAPIFY函数维护被置换的那个位置的元素。
def MAX_HEAPIFY(A, i, size):
l = LEFT(i)
r = RIGHT(i)
if l < size and A[l] > A[i]:
largest = l
else:
largest = i
if r < size and A[r] > A[largest]:
largest = r
if largest != i:
temp = A[i]
A[i] = A[largest]
A[largest] = temp
MAX_HEAPIFY(A, largest, size)
在最差情况下(最底层恰好半满)其执行时间为T(n) <= T(2/3 * n) + theta(1), 由主定理解得 T(n) = O(lg(n)), 即为树的高度。
6.3 建堆
可以利用自底向上的使用方法 MAX_HEAPIFY 来将一个无序数组变成一个最大堆。
def BUILD_MAX_HEAP(A):
size = len(A)
for i in range(len(A)//2, -1, -1):
MAX_HEAPIFY(A, i, size)
程序正确性证明:使用循环不变式,所有在i之后的元素都组成最大堆
初始化:在第一次循环迭代之前,所有i之后的元素为叶子节点没有子节点,自身组成最大堆保持:在循环i = k时,若其后的元素均为最大堆,调用MAX_HEAPIFY 方法使得A[k]与其子节点置换,故在下次迭代开始之前第k个元素之后均组成最大堆
终止:当i = 0时,其后元素(左右子树)均组成最大堆,调用MAX_HEAPIFY是的整个数组称为一个最大堆。
叶子节点个数为n/2,上一层为 n/4...高度为lg(n),第k层中每个元素的执行时间为O(lg(k))乘以每一层元素个数,在所有层求和即为其执行时间,解为O(n)。
6.4 堆排序算法
利用一个数组建一个最大堆,则第一个必为最大值,利用这个特性可以完成数组排序。
def HEAPSORT(A, size):
BUILD_MAX_HEAP(A)
for i in range(size-1, 0, -1):
temp = A[i]
A[i] = A[0]
A[0] = temp
size = size - 1
MAX_HEAPIFY(A, 0, size)
时间复杂度BUILD_MAX_HEAP花费O(n), n次MAX_HEAPIFY花费n*O(lg(n)) = O(nlg(n)),两者相加HEAPSORT的时间复杂度为 O(nlg(n))。
6.5 优先队列
优先队列,即是一个带优先级的队列,包括最大优先队列和最小优先队列,包含以下操作:
实现如下效率分别为theta(1), theta(lg(n)), theta(lg(n)), theta(lg(n)):
def HEAP_MAXIMUM(A):
return A[0]
def HEAP_EXTRACT_MAX(A, size):
assert(size > 0)
iMax = A[0]
size = size - 1
A[0] = A[size]
MAX_HEAPIFY(A, 0, size)
return iMax
def HEAP_INCREASE_KEY(A, i, key):
assert(A[i] < key)
A[i] = key
while i > 0 and A[PARENT(i)] < A[i]:
temp = A[i]
A[i] = A[PARENT(i)]
A[PARENT(i)] = temp
i = PARENT(i)
def MAX_HEAP_INSERT(A, key):
A.append(-float("inf"))
HEAP_INCREASE_KEY(A, len(A)-1, key)
习题解答