第六章 堆排序

堆排序综合了插入排序的原址(只需要常量额外空间)和归并排序时间复杂度为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))。基本过程有:

第六章 堆排序_第1张图片


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 优先队列

优先队列,即是一个带优先级的队列,包括最大优先队列和最小优先队列,包含以下操作:

第六章 堆排序_第2张图片

实现如下效率分别为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)
    


习题解答


你可能感兴趣的:(第六章 堆排序)