【Algorithm】排序之 “堆排序” 原理+python实现

堆实际上是一棵完全二叉树

完全二叉树(Complete Binary Tree): 除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐。
在这里插入图片描述
满二叉树(Perfect Binary Tree):除了叶子结点之外的每一个结点都有两个孩子,每一层(当然包含最后一层)都被完全填充。
在这里插入图片描述
完满二叉树(Full Binary Tree):除了叶子结点之外的每一个结点都有两个孩子结点。
在这里插入图片描述

堆分为大顶堆和小顶堆

  • 大顶堆满足 父节点比叶子节点大
    K e y [ i ] > = K e y [ 2 i + 1 ] & & k e y [ i ] > = k e y [ 2 i + 2 ] Key[i]>=Key[2i+1] \&\& key[i]>=key[2i+2] Key[i]>=Key[2i+1]&&key[i]>=key[2i+2]
  • 小顶堆满足 父节点比叶子节点小
    K e y [ i ] &lt; = k e y [ 2 i + 1 ] &amp; &amp; K e y [ i ] &lt; = k e y [ 2 i + 2 ] Key[i]&lt;=key[2i+1]\&amp;\&amp;Key[i]&lt;=key[2i+2] Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]

堆满足:
父节点 i i i
其子节点分别为 2 i 、 2 i + 1 2i、2i+1 2i2i+1
在这里插入图片描述

堆排序

整体的时间复杂度为 O(nlogn)
和快排对比:堆排序的数据交换次数多;堆排序数据访问的方式没有快速排序好

思路:

升序用大根堆

降序用小根堆

流程 :

索引为 1 开始(不是 0)

  1. 建堆:先把data 转换成大根堆
    1.1 从最后一个父节点 开始
    1.2 如果存在子节点大于父节点,那么值交换
    1.3 交换后 查看子节点的子节点值是不是比他大,大的话也交换,直到索引值超出或者 不存在子节点大于父节点
    1.4 父节点索引 -1 ,继续步骤1.2

  2. 排序: 对大根堆进行升序排序
    2.1 最后一个节点索引 为high
    2.2 把大根堆 根节点(索引为1)和 索引为high值 互换
    2.3 high-1 , 做堆排序
    重复2部分,直到 high =1

Example

  1. 建堆 :把 data 初始化为 大根堆:

    从最后一个非叶子节点开始 : 节点 4 (8)
    因为 13<16 16>8 , 16 和 8 位置交换
    往前遍历节点 , 节点3(19)
    因为 1<20,20>19 ,19 和 20 位置互换
    往前遍历节点 , 节点2(5)
    因为 16 > 4 5< 16 ,5 和16 位置互换
    因为 13>8 ,13>5 ,13 和5 互换
    往前遍历节点 , 节点1(7)
    因为 16<20,20>7 , 20和7互换
    因为 19>3,19>7 ,19 和7互换

在这里插入图片描述

在这里插入图片描述

  1. 排序
    建堆结束之后,堆顶元素就是最大元素,我们将其和最后一个元素进行交换,那最大元素就放到了下标为 n 的位置。然后,我们再对前面 n−1 个元素进行堆化,然后将堆顶元素放到下标为 n−1 的位置,重复这个过程,直到堆中剩余一个元素,排序也就完成了。
    在这里插入图片描述

python 实现

# 大根堆排序

def heap(data,high):    # 实现大根堆    完成一次建堆,最大值在堆的顶部(根节点)
 

    last_root = int(high/2)
    for t in range(1,last_root+1):  #  从最后一个父节点  开始,直到第一个元素(堆排序 序号从1 开始)
        i=last_root-t+1
        j=2*i

        while j<=high:
            if(j+1<=high and data[j]<data[j+1]):
                j=j+1
            if(j<=high and data[i]<data[j]):
                temp=data[i]
                data[i]=data[j]
                data[j]=temp
                i=j
                j=i*2
            else:
                break

        
def heap_sort(data):  # 排序
    high = len(data)-1
    heap(data,high)
    length=high+1

    for x in range(1,length):
        temp=data[1]
        data[1]=data[high]
        data[high]=temp
        heap(data,high-1)
        high=high-1

        
    


if __name__=='__main__':
    data=[0,50, 36, 66, 76, 36, 12, 25, 95]   # 堆排序索引从1开始
    # data=[0,1,2,3,4,5]
    print(data)
    heap_sort(data)

    print(data)

Reference

https://www.cnblogs.com/Java3y/p/8639937.html
https://www.cnblogs.com/seniusen/p/10023172.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值