Python--堆排序

堆排序 Heap Sort



前言

  • 空间复杂度
    • 只是使用了一个交换用的空间,空间复杂度就是 O(1)
  • 稳定性
    • 不稳定的排序算法

  • 是利用堆性质的一种选择排序,在堆顶选出最大值或者最小值
  • 时间复杂度
    • 堆排序的时间复杂度为 O(nlogn)
    • 由于堆排序对原始记录的排序状态并不敏感,因此它无论最好、最坏和平均时间复杂度均为 O(nlogn)

堆排序算法演示

概述

若以升序排序说明,把数组转换成最大堆积 (Max-Heap Heap) ,这是一种满足最大堆积性质 (Max-Heap Property) 的二叉树:对于除了根之外的每个结点 i , A[parent(i)] >= A[i]

重复从最大堆积取出数值最大的结点(把根结点和最后一个结点交换,把交换后的最后一个结点移出堆),并让残余的堆积维持最大堆积性质。


构建一个堆排序的三步骤

最大堆调整 (Max Heapify)

  • 将堆的末端子节点作调整,使得子节点永远小于父节点

创建最大堆(Build Max Heap)

  • 将堆中的所有数据重新排序

堆排序(HeapSort)

  • 移除位在第一个数据的根结点,并做最大堆调整的递归运算

算法实现

origin = [30, 20, 80, 40, 50, 10, 60, 70, 90]

# 定义堆排序
def heap_sort(array):
    # total 值为传入列表的长度
    total = len(origin)
    # 在输入的列表索引为0的位置插入一个0,方便后面计算
    array.insert(0,0)
    # 定义堆,进行最大堆调整
    def heap_adjust(array, total, i):
        while 2 * i < total:  # 如果 2i<total 那么i结点一定有左子孩子,索引为 2i
            lchild_index = 2 * i
            max_child_index = lchild_index  # 假设最大孩子索引为左子孩子索引
            # 如果总结点数大于左子孩子结点,那么存在右子孩子,如果右子孩子索引对应数值
            # 大于左子孩子索引数值,那么最大孩子结点索引值交换
            if max_child_index < total and array[max_child_index + 1] > array[lchild_index]:
                max_child_index = lchild_index + 1
            # 如果最大孩子索引所对的值 大于 i 结点对应的值,交换值
            if array[max_child_index] > array[i]:
                array[max_child_index], array[i] = array[i], array[max_child_index]
                i = max_child_index
            # 否则的话,打破循环
            else:
                break
    # 定义 创建最大堆的函数,将堆中的所有数据重新排序
    def max_heap(array,total):
        # 根据树的性质,做一个循环,调用 最大堆调整 来进行调整
        for i in range(total//2, 0, -1):
            heap_adjust(array, total, i)
    # 调用 创建最大堆 的函数
    max_heap(origin, total)
    # 定义 内部堆排序函数,通过判断总数大小进行循环调整,并且做一个小优化
    def _sort(array, total):
        while total >= 1:
            array[1], array[total] = array[total], array[1]
            total -= 1
            # 判断 当总数为 2时,剩下的两个数是否相等,相等就不用交换,打破循环
            if total == 2 and array[total] >= array[total -1]:
                break
            # 通过循环调用最大堆调整,来进行调整
            heap_adjust(array, total, 1)
        return array
    # 调用 内部堆排序函数
    _sort(array, total)
    # 返回值要把之前插入的 0 排除在外
    return array[1:]

print(heap_sort(origin))
print(origin)

完整代码展示

origin = [30, 20, 80, 40, 50, 10, 60, 70, 90]

def heap_sort(array):
    total = len(origin)
    array.insert(0,0)
    
    def heap_adjust(array, total, i):
        while 2 * i < total:
            lchild_index = 2 * i
            max_child_index = lchild_index
            if max_child_index < total and array[max_child_index + 1] > array[lchild_index]:
                max_child_index = lchild_index + 1
            if array[max_child_index] > array[i]:
                array[max_child_index], array[i] = array[i], array[max_child_index]
                i = max_child_index
            else:
                break
                
    def max_heap(array,total):
        for i in range(total//2, 0, -1):
            heap_adjust(array, total, i)
            
    max_heap(origin, total)

    def _sort(array, total):
        while total >= 1:
            array[1], array[total] = array[total], array[1]
            total -= 1
            if total == 2 and array[total] >= array[total -1]:
                break
            heap_adjust(array, total, 1)
        return array
        
    _sort(array, total)
    
    return array[1:]

print(heap_sort(origin))
print(origin[1:])

以上…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值