pytho分步详解堆排序

调整大顶堆

这是堆排序的基本操作,单独拿出来看得更清楚

代码

def heapadjust(arr, start, end):  # 将以start为根节点的堆调整为大顶堆
    temp = arr[start]
    # 二叉树编号为1~n,比列表索引大1
    son = 2 * start + 1
    while son <= end:
        if son < end and arr[son] < arr[son + 1]:  # 找出左右孩子节点较大的
            son += 1
        if temp >= arr[son]:  # 判断是否为大顶堆
            break

        arr[start] = arr[son]  # 子节点上移
        print("子节点上移",end="")
        print(arr)
        start = son  # 继续向下比较
        son = 2 * son + 1

    arr[start] = temp  # 将原堆顶插入正确位置
    print(arr)

案例

例子1

先看一个简单的例子

array = [1,2,3,4,5]
heapadjust(array, 1, 5)  # 1对应最后一个非叶子结点5的索引
heapadjust(array, 0, 5)  # 0对应根节点的索引

从最后一个非叶结点开始调整直到根节点都被调整,这里就是最后一个非叶子结点就是5索引为1,根节点的1索引为0,这样调整两次。
在这里插入图片描述

例子2

将那个例子加一个数,稍微加深一下理解

array = [1,2,3,4,5,6]
heapadjust(array, 2, 5)     # 2对应最后一个非叶子节点索引
heapadjust(array, 1, 5)
heapadjust(array, 0, 5)     # 0对应根节点索引

主要的变化在于需要多调用一次调整的方法
在这里插入图片描述

小结

由上面两个例子可以看出,通过循环即可调整给定列表为大顶堆。

array = [1,2,3,4,5,6]
n=len(array)
#建立大顶堆
root=n//2-1    #最后一个非叶节点(完全二叉树中)
while(root>=0):
    heapadjust(array, root, n-1)
    root-=1

执行的结果当然和例子中,手动分布执行的结果相同。
在这里插入图片描述

交换

接着上面的例1

array = [5, 4, 3, 1, 2]		# 之前构造好的大顶堆
n=len(array)
# 第一次交换取出最大
(array[0], array[n-1]) = (array[n-1], array[0])  # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-2) # 调整剩余
# 第二次交换取出次大
(array[0], array[n-2]) = (array[n-2], array[0])  # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-3) # 调整剩余
# 第三次交换取
(array[0], array[n-3]) = (array[n-3], array[0])  # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-4) # 调整剩余
# 第四次交换取
(array[0], array[n-4]) = (array[n-4], array[0])  # 将大顶堆堆顶数放到最后
heapadjust(array, 0, n-5) # 调整剩余

每次将堆顶元素即最大元素放到最后,剩余元素重新调整为大顶堆,使得剩余的最大元素能到顶堆。
在这里插入图片描述
接着将上述过程修改为循环

array = [5, 4, 3, 1, 2]
n=len(array)
i = n - 1		# 记录剩余元素部分最后一个元素对应的索引
while (i > 0):
    (array[0], array[i]) = (array[i], array[0])  # 将大顶堆堆顶数放到最后
    heapadjust(array, 0, i - 1)  # 调整剩余数组成的堆
    i -= 1

封装

最后将上述两个过程封装成可供外界调用的堆排序函数,以下代码来自另一篇博客

def  HeapSort(lst):
    def heapadjust(arr,start,end):  #将以start为根节点的堆调整为大顶堆
        temp=arr[start]
        son=2*start+1
        while son<=end:
            if son<end and arr[son]<arr[son+1]:  #找出左右孩子节点较大的
                son+=1
            if temp>=arr[son]:       #判断是否为大顶堆
                break
            arr[start]=arr[son]     #子节点上移
            start=son                     #继续向下比较
            son=2*son+1
        arr[start]=temp             #将原堆顶插入正确位置
#######
    n=len(lst)
    if n<=1:
        return lst
    #建立大顶堆
    root=n//2-1    #最后一个非叶节点(完全二叉树中)
    while(root>=0):
        heapadjust(ls,root,n-1)
        root-=1
    #掐掉堆顶后调整堆
    i=n-1
    while(i>=0):
        (lst[0],lst[i])=(lst[i],lst[0])  #将大顶堆堆顶数放到最后
        heapadjust(lst,0,i-1)    #调整剩余数组成的堆
        i-=1
    return lst

调用起来看看

array = [1,3,6,2,4,5]
print(HeapSort(array))

成功得到升序排列的数组
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值