python实现堆排序 (附解析)

python 实现堆排序

堆排序:
堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。(来源于百度百科)
就是利用完全二叉树的性质,将一个长数组划分为若干个小块,进行比较交换,进而达到排序的目的。基本思想还是化整体为局部,然后局部合并达到高效排序的目的。
核心概念:
大(小)顶堆
父节点
子节点
具体概念这里就不贴了,以前遇到算法相关问题,我当时只是靠死记硬背,发现如果不能理解算法核心思想,记再多的代码也没用,只要能深入理解算法的核心思想,面试的时候哪怕当时没写出来,也能讲出个大概,开发本来就是一件很烧脑的工作,大家一起共勉。
下面给出详细代码:

# 堆排序
# 堆排序为一种选择排序,最坏,最好,平均复杂度都是O(nlogn),不稳定排序
# 算法核心,从最后的子树开始递归,使得父节点的值最大,最后将首尾元素调换位置
# 算法核心类似希尔排序,只是分组形式不同,思想相同

import random
import time
new_l = []

# 自定义装饰器,返回当前函数执行时间
def timing(func):
    def deact(*args,**kwargs):
        s_time = time.time()
        ref = func(*args,**kwargs)
        e_time = time.time()
        print("{} 函数 执行之间为{}".format(func.__name__,e_time-s_time))
        return ref
    return deact

# 算法核心为递归待排序数据构建的完全二叉树的每个子树,使得每个父节点值为最大
def heap_sort(l):
    # 根据完全二叉树性质,得出所有父节点对应的待排序的数据的索引
    # 最后一个父节点索引为 len(l) // 2 - 1 ,所有父节点列表为 0 到 len(l) // 2 - 1
    # 父节点两个子节点索引值(如果存在的话)左子节点 2*i + 1,右子节点 2*i + 2 其中i 为父节点
    # 每一轮比较涉及所有树的的比较
    # 这里把完全二叉树所有非子叶节点和数组索引进行结合,不需要构造二叉树,但可以利用二叉树的特性进行排序
    global new_l
    last_p_index = len(l) // 2 - 1
    if len(l) == 0:
        return
    while last_p_index >= 0:
        if 2 * last_p_index + 2 < len(l) -1:  # 证明最后一个非子叶节点存在右孩子,此节点必定存在左孩子
            if l[2 * last_p_index + 2] > l[last_p_index]:
                l[2*last_p_index+2],l[last_p_index] = l[last_p_index],l[2*last_p_index+2]   # 交换右孩子
        if l[2 * last_p_index + 1] > l[last_p_index]:
            l[2 * last_p_index + 1], l[last_p_index] = l[last_p_index], l[2 * last_p_index + 1]  # 交换左孩子
        last_p_index -= 1
    new_l.insert(0,l[0])
    l = l[1:]
    heap_sort(l)

if __name__ == '__main__':
    l = [random.randint(5,100) for x in range(300)]
    print(l)
    heap_sort(l)
    print(new_l)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值