堆排序

堆排序的时间复杂度是O(nlg(n)),并且具有空间原址性

二叉堆heap是一种数据结构,可用来实现优先队列

给定一个节点的下标i(下标从0开始),则其父节点、坐孩子、右孩子坐标:
parent(i) = (i+1)//2 - 1 = ((i + 1) >> 1) - 1
left(i) = 2*i + 1 = (i << 1) + 1
right(i) = 2*i + 2 = (i + 1) << 1

最小堆定义: 任意 i 满足 A[parent(i)] <= A[i]
最大堆定义: 任意 i 满足 A[parent(i)] >= A[i]

在堆排序中,使用最大堆
在优先队列算法中,使用最小堆
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

class Heap():
    def __init__(self, seq, heapSize, length):
        """
        seq: 存放待排序的序列
        heapSize: 堆的大小
        lenght: 整个序列大小
        """
        self.seq = seq
        self.heapSize = heapSize
        self.length = length


def heapSort(seq):
    """
    堆排序算法
    """
    heap = Heap(seq, len(seq), len(seq))
    __buildMaxHeap(heap)
    s = heap.seq
    for i in range(heap.length - 1, 0, -1):
        s[0], s[i] = s[i], s[0]
        heap.heapSize -= 1
        __maxHeapify(heap, 0)


def __maxHeapify(heap, i):
    """
    前提是 i 的两棵子树 left(i) 和 right(i) 的二叉树都是最大堆了
    现在加入 i 节点后,要保持这个二叉树为最大堆的性质
    heap: Heap 数据结构
    """
    seq = heap.seq
    slen = heap.heapSize

    while True:
        left = (i << 1) + 1
        right = (i + 1) << 1
        if left < slen and seq[left] > seq[i]:
            largest = left
        else:
            largest = i
        if right < slen and seq[right] > seq[largest]:
            largest = right
        if largest != i:
            seq[largest], seq[i] = seq[i], seq[largest]
            i = largest
        else:
            break


def __buildMaxHeap(heap):
    """
    由完全二叉树的性质可知:对于 n//2..n-1 为下标的元素,都是叶子节点,
    那么可从下标 (n+1)//2 - 1 开始往前到 0 的元素调用 maxHeapify
    heap: Heap数据结构
    """
    slen = heap.heapSize
    for i in range(((slen + 1) >> 1) - 1, -1, -1):
        __maxHeapify(heap, i)


if __name__ == '__main__':
    seq = [9, 7, 8, 10, 16, 3, 14, 2, 1, 4]
    heapSort(seq)
    print(seq)