位置: 编程技术 - 正文

Python实现二叉堆(python 二叉堆)

编辑:rootadmin

推荐整理分享Python实现二叉堆(python 二叉堆),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:python构建二叉树,python二叉树算法,python 二叉堆,python 二叉堆,python二叉排序树怎么构造,python 二叉堆,python二叉排序树怎么构造,python 二叉堆,内容如对您有帮助,希望把文章链接给更多的朋友!

优先队列的二叉堆实现

在前面的章节里我们学习了“先进先出”(FIFO)的数据结构:队列(Queue)。队列有一种变体叫做“优先队列”(Priority Queue)。优先队列的出队(Dequeue)操作和队列一样,都是从队首出队。但在优先队列的内部,元素的次序却是由“优先级”来决定:高优先级的元素排在队首,而低优先级的元素则排在后面。这样,优先队列的入队(Enqueue)操作就比较复杂,需要将元素根据优先级尽量排到队列前面。我们将会发现,对于下一节要学的图算法中的优先队列是很有用的数据结构。

我们很自然地会想到用排序算法和队列的方法来实现优先队列。但是,在列表里插入一个元素的时间复杂度是O(n),对列表进行排序的时间复杂度是O(nlogn)。我们可以用别的方法来降低时间复杂度。一个实现优先队列的经典方法便是采用二叉堆(Binary Heap)。二叉堆能将优先队列的入队和出队复杂度都保持在O(logn)。

二叉堆的有趣之处在于,其逻辑结构上像二叉树,却是用非嵌套的列表来实现。二叉堆有两种:键值总是最小的排在队首称为“最小堆(min heap)”,反之,键值总是最大的排在队首称为“最大堆(max heap)”。在这一节里我们使用最小堆。

二叉堆的操作

二叉堆的基本操作定义如下:

BinaryHeap():创建一个空的二叉堆对象 insert(k):将新元素加入到堆中 findMin():返回堆中的最小项,最小项仍保留在堆中 delMin():返回堆中的最小项,同时从堆中删除 isEmpty():返回堆是否为空 size():返回堆中节点的个数 buildHeap(list):从一个包含节点的列表里创建新堆

下面所示代码是二叉堆的示例。可以看到无论我们以哪种顺序把元素添加到堆里,每次都是移除最小的元素。我们接下来要来实现这个过程。

为了更好地实现堆,我们采用二叉树。我们必须始终保持二叉树的“平衡”,就要使操作始终保持在对数数量级上。平衡的二叉树根节点的左右子树的子节点个数相同。在堆的实现中,我们采用“完全二叉树”的结构来近似地实现“平衡”。完全二叉树,指每个内部节点树均达到最大值,除了最后一层可以只缺少右边的若干节点。图 1 所示是一个完全二叉树。

图 1:完全二叉树

有意思的是我们用单个列表就能实现完全树。我们不需要使用节点,引用或嵌套列表。因为对于完全二叉树,如果节点在列表中的下标为 p,那么其左子节点下标为 2p,右节点为 2p+1。当我们要找任何节点的父节点时,可以直接使用 python 的整除。如果节点在列表中下标为n,那么父节点下标为n//2.图 2 所示是一个完全二叉树和树的列表表示法。注意父节点与子节点之间 2p 与 2p+1 的关系。完全树的列表表示法结合了完全二叉树的特性,使我们能够使用简单的数学方法高效地遍历一棵完全树。这也使我们能高效实现二叉堆。

堆次序的性质

我们在堆里储存元素的方法依赖于堆的次序。所谓堆次序,是指堆中任何一个节点 x,其父节点 p 的键值均小于或等于 x 的键值。图 2 所示是具备堆次序性质的完全二叉树。

图 2:完全树和它的列表表示法

二叉堆操作的实现

接下来我们来构造二叉堆。因为可以采用一个列表保存堆的数据,构造函数只需要初始化一个列表和一个currentSize来表示堆当前的大小。Listing 1 所示的是构造二叉堆的 python 代码。注意到二叉堆的heaplist并没有用到,但为了后面代码可以方便地使用整除,我们仍然保留它。

Listing 1

我们接下来要实现的是insert方法。首先,为了满足“完全二叉树”的性质,新键值应该添加到列表的末尾。然而新键值简单地添加在列表末尾,显然无法满足堆次序。但我们可以通过比较父节点和新加入的元素的方法来重新满足堆次序。如果新加入的元素比父节点要小,可以与父节点互换位置。图 3 所示的是一系列交换操作来使新加入元素“上浮”到正确的位置。

Python实现二叉堆(python 二叉堆)

图 3:新节点“上浮”到其正确位置

当我们让一个元素“上浮”时,我们要保证新节点与父节点以及其他兄弟节点之间的堆次序。当然,如果新节点非常小,我们仍然需要将它交换到其他层。事实上,我们需要不断交换,直到到达树的顶端。Listing 2 所示的是“上浮”方法,它把一个新节点“上浮”到其正确位置来满足堆次序。这里很好地体现了我们之前在headlist中没有用到的元素 0 的重要性。这样只需要做简单的整除,将当前节点的下标除以 2,我们就能计算出任何节点的父节点。

在Listing 3 中,我们已经可以写出insert方法的代码。insert里面很大一部分工作是由percUp函数完成的。当树添加新节点时,调用percUp就可以将新节点放到正确的位置上。

Listing 2

Listing 3

我们已经写好了insert方法,那再来看看delMin方法。堆次序要求根节点是树中最小的元素,因此很容易找到最小项。比较困难的是移走根节点的元素后如何保持堆结构和堆次序,我们可以分两步走。首先,用最后一个节点来代替根节点。移走最后一个节点保持了堆结构的性质。这么简单的替换,还是会破坏堆次序。那么第二步,将新节点“下沉”来恢复堆次序。图 4 所示的是一系列交换操作来使新节点“下沉”到正确的位置。

图 4:替换后的根节点下沉

为了保持堆次序,我们需将新的根节点沿着一条路径“下沉”,直到比两个子节点都小。在选择下沉路径时,如果新根节点比子节点大,那么选择较小的子节点与之交换。Listing 4 所示的是新节点下沉所需的percDown和minChild方法的代码。

Listing 4

Listing 5 所示的是delMin操作的代码。可以看到比较麻烦的地方由一个辅助函数来处理,即percDown。

Listing 5

关于二叉堆的最后一部分便是找到从无序列表生成一个“堆”的方法。我们首先想到的是,将无序列表中的每个元素依次插入到堆中。对于一个排好序的列表,我们可以用二分搜索找到合适的位置,然后在下一个位置插入这个键值到堆中,时间复杂度为O(logn)。另外插入一个元素到列表中需要将列表的一些其他元素移动,为新节点腾出位置,时间复杂度为O(n)。因此用insert方法的总开销是O(nlogn)。其实我们能直接将整个列表生成堆,将总开销控制在O(n)。Listing 6 所示的是生成堆的操作。

Listing 6

图 5:将列表[ 9, 6, 5, 2, 3]生成一个二叉堆

图 5 所示的是利用buildHeap方法将最开始的树[ 9, 6, 5, 2, 3]中的节点移动到正确的位置时所做的交换操作。尽管我们从树中间开始,然后回溯到根节点,但percDown方法保证了最大子节点总是“下沉”。因为堆是完全二叉树,任何在中间的节点都是叶节点,因此没有子节点。注意,当i=1时,我们从根节点开始下沉,这就需要进行大量的交换操作。可以看到,图 5 最右边的两颗树,首先 9 从根节点的位置移走,移到下一层级之后,percDown进一步检查它此时的子节点,保证它下降到不能再下降为止,即下降到正确的位置。然后进行第二次交换,9 和 3 的交换。由于 9 已经移到了树最底层的层级,便无法进一步交换了。比较一下列表表示法和图 5 所示的树表示法进行的一系列交换还是很有帮助的。

下列所示的代码是完全二叉堆的实现。

能在O(n)的开销下能生成二叉堆看起来有点不可思议,其证明超出了本书的范围。但是,要理解用O(n)的开销能生成堆的关键是因为logn因子基于树的高度。而对于buildHeap里的许多操作,树的高度比logn要小。

Python解析树及树的遍历 解析树完成树的实现之后,现在我们来看一个例子,告诉你怎么样利用树去解决一些实际问题。在这个章节,我们来研究解析树。解析树常常用于真实

Python内建数据结构详解 一、列表(List)list是一个可以在其中存储一系列项目的数据结构。list的项目之间需用逗号分开,并用一对中括号括将所有的项目括起来,以表明这是

Python连接mysql数据库的正确姿势 Python数据库接口支持非常多的数据库,你可以选择适合你项目的数据库:GadFlymSQLMySQLPostgreSQLMicrosoftSQLServerInformixInterbaseOracleSybase不同的数据库你需要

标签: python 二叉堆

本文链接地址:https://www.jiuchutong.com/biancheng/382322.html 转载请保留说明!

上一篇:Python实现二叉搜索树(python二叉树)

下一篇:Python解析树及树的遍历(树的python)

  • 所得税分录是怎么计算的
  • 申报个人所得税在哪里报
  • 材料采购成本是主营业务成本吗
  • 税控盘及服务费会计分录
  • 发票税率金额如何得出
  • 增值税小规模纳税人优惠政策
  • 房产经纪公司成本费用
  • 企业最常用的业务分录
  • 进项税当月申报怎么申报
  • 进项税留底是什么意思
  • 商业承兑汇票风险大吗
  • 个体户查账征收怎么交税?
  • 编制竣工结算的具体增减内容有哪几个方面?
  • 从国外进口的免税商品
  • 公司付给职工的工资
  • 非货币性资产对外投资
  • 股权转让以前年度怎么算
  • 减免税费期末如何结转
  • 设计费开专用发票几个点
  • 应征增值税不含税销售额(3%征收率)怎么算
  • 股权转让印花税税率是多少
  • 营改增后融资租赁税率
  • 购房房产税如何支付
  • 企业所得税税率2.5% 5% 25%
  • 增值税销项税额抵减账务处理
  • win10如何设置闹钟
  • 厂区地面硬化的意义
  • dmc32.dll
  • 寿命最短的苹果手机
  • 魅族路由器怎么样
  • 元宇宙band
  • 职工教育经费计入管理费用吗
  • 解决安装后软件icon一圈白边问题
  • 结转工资费用
  • php获取post请求参数
  • gpt3 plug
  • 若依框架前端发请求
  • 软件折旧费
  • 游戏microsoft visual c++ runtime
  • 合并报表为什么要抵消子公司所有者权益
  • 视同销售到底如何纳税调整?
  • 高新企业做账有什么不同
  • 图文详解管道支架制作安装标准
  • 如何解决安装包解析错误
  • 发票商品分类
  • 有限公司分公司属于什么类型
  • 事业单位长期应付款呆账怎样处理好
  • 劳务公司已开票怎么入账
  • 专项应付款转资本公积需要缴纳所得税
  • 投资性房地产租金
  • 欠款在公司注销怎么处理
  • 开发成本的会计科目编码
  • 外贸出口企业申报年月怎么填
  • 新股东入股的账务处理
  • 费用暂估入账后期如何冲销
  • 固定资产清理借方增加还是减少
  • 政府补贴项目需要审批吗
  • 注册资本金印花税税率是2.5还是5
  • 生产性生物资产账务处理
  • 房屋销售预收如何交税
  • sql语句学习
  • mysql实现合并同一ID对应多条数据的方法
  • mac如何设置启动系统
  • win7系统屏幕键盘怎么打开
  • 电脑win 8系统
  • 这张图告诉我们什么道理
  • Win10怎么打开屏幕键盘
  • 强缓存标志
  • angular创建项目命令
  • 如何让卖家给你乖乖退款
  • nodejs数据加密
  • node.js中使用文件流进行文件复制,首先需要创建一个
  • javascript入门教学
  • EasyTouch Broadcast messages选项在js和c#下的用法
  • python入门小程序编写
  • python 中文转码
  • 周报要素
  • 综合所得税包括哪些内容
  • 湖北低保查询网站官网
  • 公车补贴计入工资吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设