python 堆排序

堆排序是对选择排序的一种优化算法,都属于选择排序类。

基本过程:堆是一种完全二叉树,是一种树形选择结构,将待排序的序列构造成一个大顶堆(即每个节点的值都大于或等于其左右孩子节点的值),然后将堆顶的根节点移走,与堆数组的末尾元素交换,此时末尾元素就是最大值。再将剩余的n-1个序列重新构造一个堆,得到次大值置于末尾,反复执行得到一个有序序列。

过程可参考如下图:

                                

这里需要注意的,堆排序为了方便完全二叉树的计数,序列的首位置为空,忽略不计。

示例代码如下:

def heap_sort(lst):
    n = len(lst)-1              # 这里注意根据python的range列表的性质,要将序列长度减一,否则列表长度溢出
    for i in range(n/2, 0, -1):
        heap_adjust(lst, i, len(lst))

    while n > 1:
        lst[1], lst[n] = lst[n], lst[1]   # 将堆顶记录和当前未经排序子序列的最后一个记录交换
        heap_adjust(lst, 1, n)            # 将lst[n]重新调整为大顶堆
        n -= 1
    return lst[1:]                      # 这里为了方便完全二叉树的计数,将序列中的首个元素置为空忽略不计

def heap_adjust(lst, k, size):      # 自顶向下堆化,从k开始堆化
    N = size - 1
    while 2 * k <= N:
        lchild = 2 * k
        rchild = 2 * k + 1
        if lchild < N and lst[lchild] < lst[rchild]:  # 选出左右孩子节点中更大的那个,并将关键字赋值给左孩子
            lchild = rchild
        if lst[k] < lst[lchild]:                      # 将左孩子与父节点比较,选出大的
            lst[k], lst[lchild] = lst[lchild], lst[k]
            k = lchild              # 将k扩倍,对孙节点排序
        else:
            break


if __name__ == "__main__":
    start = time.clock()

    rand_lst = []
    for i in range(10):
        rand_lst.append(round(random.random()*100, 2))
    lst = heap_sort(rand_lst)

    end = time.clock()
    print lst
    print "done  ", (end-start)

性能方面:

堆排序的运行时间主要消耗在初始构建堆和重建堆的反复筛选上

由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度都为O(nlogn),空间复杂度上它只有一个用来交换的暂存单元,所以为O(1),但是由于记录的比较和交换是跳跃进行的,所以堆排序是不稳定的排序方法。此外,由于它的性能主要消耗在堆的创建与重建上,所以不适合排序序列少的情况。

原文地址:https://www.cnblogs.com/webber1992/p/6140850.html