每日一问6.22

堆排序的python实现

思路分析:

  1. 使用列表存储
  2. 从后向前调用堆调整算法建立最大堆,使用O(nlogn)
  3. 交换首尾元素
  4. 调整前n-1个元素成最大堆,使用O(logn)
  5. 交换前n-1个元素的首尾元素
  6. 调整前n-2个元素成最大堆
  7. 交换前n-2个元素的首尾元素
  8. 直到调整前2个元素成最大堆
  9. 交换前2个元素的首尾元素
def exchange(alist, i, j):
    alist[i], alist[j] = alist[j], alist[i]
    
def build_max_heap(alist):
    for i in range(len(alist)-1, -1, -1):
        tune_heap(alist, i, len(alist))

def tune_heap(alist, start, max_index_one):
    left = 2 * start + 1
    right = left + 1
    if right<max_index_one:
        tmp = right if alist[right]>alist[left] else left
    elif left<max_index_one:
        tmp = left
    else:
        return
    if alist[start]<alist[tmp]:
        exchange(alist, start, tmp)
        tune_heap(alist, tmp, sub_length)
    
def sort(alist):
    build_max_heap(alist)
    for i in range(1, len(alist)):
        exchange(alist, 0, -1*i) # 最后一次交换是交换前2个元素
        tune_heap(alist, 0, len(alist)-i))


if __name__=="__main__":
    alist = [22, 3, 5, 8, 0]
    alist = []
    alist = [1]
    alist = [2,1]
    sort(alist)
    print(alist)

实现中的坑:

  1. exchange的实现中必须使用列表作为参数,不可以使用普通变量,函数不会改变不可变的实参,但是可以改变可变实参,列表是可变实参。
  2. tune_heap的实现中不可以使用列表的子切片作为实参,必须使用原始的整个列表,因为列表的切片是浅拷贝,改变浅拷贝不影响原始列表。
  3. 节点i的左节点index是2*i+1不是2*i,因为列表编号从0开始。

要点:

  1. 建最大堆,仅仅从后向前与父节点交换是不行的,因为不能保证任意节点的值一定不大于父节点的值,比如alist=[22, 3, 44, 0, 66],第二大的元素44不会跑到第二层去(它会跑到最后去)。需要从后向前不断调用调整堆算法。
  2. 调整堆中,在左右子节点存在一个时,使用tmp变量保存值最大的那个子节点索引是比较好的方法 。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值