最大堆(二)

背景知识:

  1. 堆是一棵完全二叉树,什么是完全二叉树?就是除了最后一层节点之外,其他层的节点个数必须是最大值,并且最后一层的节点必须都集中在左侧。
  2. 堆分为最大堆和最小堆。最大堆就是父节点大于等于子节点,从而导致根节点是最大值。最小堆就是父节点小于等于子节点,从而导致根节点是最小值。本文基于最大堆讲解,并且提供python代码实现。

1.在第一节中我们详细讲解了什么是最大堆,以及基于列表这种数据结构的最大堆的python实现方案,聪明的小伙伴可能已经发现在第一节中,我们将原列表数据变成堆的过程是循坏执行了一个叫做Shift Up的方法,那这么做效率是不是不高呢?答案是肯定,为此我们对原来的堆类进行优化,使用Heapify算法

2.首先简单介绍一下Heapify算法:一个最大堆,从上而下从左到右,依次从1开始标序直到最后一个节点,这时候你可以发现一个规律:从下往上,第一个非叶子节点的序号是节点总个数除以二取整。Heapify算法就是以这个规律为基础,对于原列表构建堆的过程不在是循环执行Shift Up,而是直接忽略叶子节点,从第一个非叶子节点开始,向上追溯,把每一部分当作是一棵完全二叉树执行Shift Down来构建最大堆,直至追溯到根节点,那么整棵完全二叉树就是一个最大堆了。具体的图解如下:

3.经过了第二步的分析,相信读者对于Heapify算法已经很清楚了,下面提供python的具体实现:

import random
# 使用heapify算法优化(heapify算法其实就是只考虑非叶子节点,并向上追溯将每一部分看成一个完全二叉树并执行shiftDown变成最大堆,
# 直至向上追溯到下标为1,那么整个完全二叉树就是一个最大堆了。
class maxStack1:
    def __init__(self, list, n):
        self.data = [0]
        for i in range(n):
            self.data.append(list[i])
        self.count = n
        # heapify算法
        # self.count//2得到的就是第一个非叶子节点的下标,-1表示向上追溯
        for key in range(self.count // 2, 0, -1):
            self.__shiftDown(key)


    # 首先比较当前节点的两个子节点的大小,如果大的那个子节点比父元素大就交换位置
    def __shiftDown(self, key):
        # 在完全二叉树中,只要保证有左节点那么这个节点就是有孩子的,因为完全二叉树并不存在有右节点而没有左节点
        while 2 * key <= self.count:
            # 默认change指向左节点
            change = 2 * key
            # 如果存在右节点并且右节点比左节点大,那么将change加1,此时change指向了右节点
            if change + 1 <= self.count and self.data[change + 1] > self.data[change]:
                change += 1
            # 经过上面两步,此时change指向的值是key父节点最大的孩子节点
            if self.data[change] <= self.data[key]:
                break
            self.data[change], self.data[key] = self.data[key], self.data[change]
            key = change


if __name__ == '__main__':
    n=10
    list=[random.randint(0,n) for i in range(n)]
    print(list)
    maxStack = maxStack1(list,n)
    print(maxStack.data)

4.堆排序的时间消耗主要在初始堆的构建和反复重建堆这两部分上,第一节中我们使用循环执行Shift Up来构建初始堆,时间复杂度是O(NlogM),经过Heapify算法优化之后,构建初始堆的时间复杂度变为了O(N)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值