Fighting-算法-堆排序

"""
    堆排序:是一种树形选择排序方法,特点:
    在排序的过程中,将L[1...n]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,
    在当前无序区中选择关键字最大(或最小)的元素。
    堆的定义如下:
        n个关键字序列L[1...n]称为堆,当且仅当该序列满足: 
        1、 L(i) <= L(2i) { L(i) <= L(2i+1)} 满足此公式的称为小根堆
        2、 L(i) >= L(2i) { L(i) >= L(2i+1)} 满足此公式的称为大根堆
        (其中1 =< i <= {n/2}向下取整 )
    显然,在大根堆中,最大的元素存放在根节点中,且对其任一非根结点,它的值小于或者等于其双亲结点的值。
    堆排序的思想(以大根堆为例):
        堆排序的关键是构造初始堆,对初始序列建堆,就是一个反复筛选的过程。
        1、首先将待排序的数组构造出一个大根堆(自下往上逐步调整为大根堆):
        
            建堆的思路:n个结点完全的二叉树,最后一个结点是第{n/2}个结点的孩子。
            对以{n/2}结点为根的子树筛选:(大根堆:若根结点的关键字小于左右子女中关键字较大者则交换),使该子树成
        为堆。之后向前依此对以各结点(n/2-1 ~ 1)为根的子树进行筛选,看该结点值是否大于其左右子结点的值,若不是,
        将左右子结点中较大值与之交换,交换后可能破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到以该结点
        为根的子树构成堆为止。
        
        2、取出这个大根堆的堆顶结点(最大值),与堆的最下最右的元素进行交换,把剩下的元素再构造出一个大根堆
        
        3、重复第二步,直到这个大根堆的长度为1,此时完成排序。
        

"""
# Python的collections库里提供了链表结构deque,我们先使用它初始化一个无序序列:
from collections import deque


def swap_param(L, i, j):
    L[i], L[j] = L[j], L[i]
    return L


def heap_adjust(L, start, end):
    """
    删除堆顶元素时,先将最后一个元素与堆顶元素交换,由于此时破坏了堆的性质,需要
    对此时根结点进行向下调整操作。
    :param L:
    :param start:
    :param end:
    :return:
    """
    # 对以[n/2]结点为根的子树筛选,temp 暂存根节点start
    temp = L[start]
    i = start
    j = 2 * i
    # 沿着key(关键字)较大的子结点向下筛选
    while j <= end:
        # 保证 j 取到左右子树中关键字较大的值
        if (j < end) and (L[j] < L[j + 1]):
            j += 1
        if temp < L[j]:
            L[i] = L[j]
            i = j
            j = 2 * i
        else:
            # 筛选结束:temp>=L[j]:说明根结点的关键字最大。
            break
    L[i] = temp


def adjust_up(L, k):
    """
    对堆进行插入操作,先将新结点放在堆的末端,对新结点执行向上调整。
    :param L:
    :param k: 向上调整的结点,也为堆的元素个数
    :return:
    """
    temp = L[k]
    i = k // 2
    while i > 0 and L[i] < L[0]:
        L[k] = L[i]
        k = i
        i = k //2
    L[k] = temp


def heap_sort(L):
    """
    因为引入了一个辅助空间,所以使L_length = len(L) - 1
    第一个循环做的事情是把序列调整为一个大根堆(heap_adjust函数)
    第二个循环是把堆顶元素和堆末尾的元素交换(swap_param函数),然后把剩下的元素调整为一个大根堆(heap_adjust函数)

    :param L:
    :return:
    """
    L_length = len(L) - 1

    first_sort_count = L_length // 2
    #  从i = [n/2]-1 ,反复调整堆
    for i in range(first_sort_count):
        heap_adjust(L, first_sort_count - i, L_length)

    for i in range(L_length - 1):
        L = swap_param(L, 1, L_length - i)
        heap_adjust(L, 1, L_length - i - 1)

    return [L[i] for i in range(1, len(L))]


if __name__ == '__main__':
    L = deque([50, 16, 30, 10, 60, 90, 2, 80, 70])
    L.appendleft(0)
    print(heap_sort(L))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值