基于pyton3的堆排序

本文介绍了基于Python3的堆排序算法,首先解释了完全二叉树和大根堆的概念,接着阐述如何通过数组表示完全二叉树,并详细描述了大根堆的构建过程。在实现过程中,通过不断调整大根堆并交换最大值来完成排序。最后,讨论了堆排序的时间复杂度和额外空间复杂度。
摘要由CSDN通过智能技术生成

一直想把常见的排序算法,都写一遍。今天,终于完成了。打卡之堆排序。

堆排序算法,主要利用到完全二叉数以及大根堆的概念。完全二叉数: 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。 大根堆:任何一颗子树的最大值都是它本身。

通常情况下,如果你理解了完全二叉数的概念,那么完全二叉数就可以用一个数组来进行表示。

eg:nums=[1,2,3,4,5,6]

 如果用数组表示完全二叉数的话,假设下标为i的元素,那么它的左孩子:2*i+1  右孩子为2*i+2  它的父节点为(i-1)//2

ok,那我先来看看大根堆是如何实现的:

def heapinsert(alist, i):
    while alist[i] > alist[(i-1)//2] and i!=0:
        alist[i], alist[(i-1)//2] = alist[(i-1)//2], alist[i]
        i = (i - 1) // 2
nums=[1,3,5,4,2,6]
for i in range(len(nums)):
    heapinsert(nums,i)

我们从下往上将每一颗子树的根都调换成该子树的最大值。eg:nums=[1,3,5,4,2,6]  变成:nums=[6,4,5,1,2,3]

 相当于做一次大根堆的操作,我们就得到了完全二叉数中的最大值。那我们就可以对数组每次操作大根堆,然后将下标为0的元素与数组最后一位进行元素交换。那数组中的最大值就得到了。 eg:nums=[6,4,5,1,2,3] 转变以后 nums=[3,4,5,1,2,6]。但是这会破坏大根堆的有序性。所以,我们每交换一次,则需要对大根堆进行调整。这个时候我们需要将置换厚的元素从上到下与其左右孩子做比较,往下沉,重新得到一个大根堆(注意,当我们将最大值交换以后,相当与数组的长度减1,不考虑数组末尾的值,因为此时末尾元素,已经排好序了,就是待排数组的最大值)。

def heapify(alist, index, size):
    left = index*2+1
    while left <= size:
        largest = left+1 if left+1 <= size and alist[left] < alist[left+1] else left
        largest = index if alist[index] > alist[largest] else largest
        if largest == index:
            break
        alist[largest], alist[index] = alist[index], alist[largest]
        index = largest
        left = index*2+1

 然后,我们来看看整体代码:

def heapsort(alist):
    length = len(alist)
    #首先对数组进行大根堆排序
    for i in range(length):
        heapinsert(alist, i)
    for j in range(length-1, 0, -1):
        #置换堆顶与树末尾的值
        alist[0], alist[j] = alist[j], alist[0]
        #每次对前j-1个数重新进行大根堆排序
        heapify(alist, 0, j-1)

def heapinsert(alist, i):
    while alist[i] > alist[(i-1)//2] and i!=0:
        alist[i], alist[(i-1)//2] = alist[(i-1)//2], alist[i]
        i = (i - 1) // 2

def heapify(alist, index, size):
    left = index*2+1#获取当前节点的子节点
    #限制数组边界,只排未排好序的数组
    while left <= size:
        #获取左右孩子较大值的下标
        largest = left+1 if left+1 <= size and alist[left] < alist[left+1] else left
        #获取当前节点与左右孩子中最大值中较大值的下标
        largest = index if alist[index] > alist[largest] else largest
        #对比完,如果当前仍是最大值,则已符合大根堆,则退出此次循环
        if largest == index:
            break
        #不然,使子树中根的值最大
        alist[largest], alist[index] = alist[index], alist[largest]
        #将当前节点置为先前最大值的下标,继续排序
        index = largest
        left = index*2+1
if __name__ == '__main__':
    #获取一个整数数组
    nums = list(map(int, input().split()))
    #对其进行排序
    heapsort(nums)
    print(nums)

堆排序的时间复杂度为O(n*logn)  额外空间复杂度为O(1)。如果只是建立一个堆,花费时间为O(n)

给个前面已完成的排序算法链接:

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值