数据结构(邓俊辉)学习笔记】优先级队列 09——左式堆:合并算法

news2024/9/20 8:15:24

文章目录

  • 1. LeftHeap模板类
  • 2. 算法
  • 3. 实现
  • 4. 实例

1. LeftHeap模板类

接下来这节,来讨论左式堆的合并算法。再给出具体算法之前,首先要给出左式堆模板类的定义。
在这里插入图片描述

比如这就是一种可能的实现方式,可以看到,我们这里再次利用了 C++的多重继承,只不过与完全二叉堆不同,既然左式堆已经不再满足结构性,所有元素在物理上也不可能继续保持紧密的排列,因此继续从向量进行派生已经不合时宜,而实际上在这样的场合中,灵活地改用树形结构作为派生的基类则是一种更加高效的方法。同样地,这里依然需要以优先级队列接口为"神",而取代向量的二叉树则扮演着"形"的角色。

既然同样的派生自 PQ, 左式堆也自然地应该提供优先级队列的三个标准接口,而根据这里的实现方式,最大元总是始终对应于根节点。因此,为了取出最大元,我们只需将根节点的数据域返回即可。

接下来我们就可以通过外部函数的形式给出将两个左式堆合并的具体算法。

2. 算法

实际上,采用递归的模式,左式堆合并算法可以非常简明地描述并实现。
在这里插入图片描述
来看一个一般的场景,假设待合并两个堆,分别以 a 和 b 为根,并且假设在抵达递归基之前,它们的左右子堆都是存在的。

我们可以借助递归将 a、b两个堆合并的问题转化为这样一个问题:具体来说也就是我们需要将 a 的右子堆取出,并且递归的与刚才的堆 b 完成合并,合并所得的结果继续作为 a 的右子堆。

当然,为了保证 a 在此后继续满足左倾性,在这次合并返回之后,我们还需比较 a_L 与合并之后这个堆的 NPL 值,如果有必要,我们还需另二者互换位置。

没错,整个算法就是这样的简单明了,尽管它的实现还需要破费一些功夫。

3. 实现

现在,我们就来将刚才的算法原理兑现为具体的代码。
在这里插入图片描述
比如这就是一种可能的实现方式,可以看到这是一个递归式的算法。

作为递归基,总共有两种情况,对应于待合并的堆中至少一个为空的情况。事实上只要其中一个为空,我们就直接返回另一个即可。

因此,当算法执行到这一句的时候(第三句)可以确认两个堆都不是空的,此时我们要比较两个根节点在数值上的大小,如果有必要,应将二者互换名称。从而保证在数值上 a 总是不小于 b,以便在后续递归的合并过程中将 b 作为 a 的后代。

接下来是核心的一步,我们需要递归地将 a 的右子堆与 b 进行合并。得益于递归的机制,接下来我们就可以假设这次合并的确完成。

因此接下来我们要在 a 及其新的右子树之间建立起一个正确的连接。

在完成了这样的拓扑连接之后,我们还需要进一步的确认 a 满足左倾性。也就是说就 NPL 而言,如果当前的左子堆要小于已右子堆,则需要将二者互换位置,

最后我们还需要根据 NPL 的定义及时地更新 a 的 NPL 值。

至此算法方可顺利返回。

4. 实例

以下,就来通过一个具体的实例加深对左式堆合并算法的理解和领悟:
在这里插入图片描述
假设在这里,我们需要将一个规模为4的堆与另一规模为3的堆合并起来。

  1. 首先通过比较,我们能确认前者的树根在数值上要大于后者的树根,因此二者无需互换,我们分别称之为 a 和 b。

  2. 相应的,a 的右孩子也自然就是12,于是按照算法,我们将原先的问题转化为 a 的右子堆与 b 堆的合并问题。

  3. 在新的这个递归层次,我们依然需要比较两个子堆的根节点,因为在数值上15更大,所以此时我们应该将它们互换名称,将前者记作 b,而将后者记作 a。于是问题进而转化为这样的形式,也就是说将15这个堆与12这个堆进行合并。

  4. 既然此时的 a 是15,所以 a 的右子树也自然就是8,是按照算法的流程,问题进一步转化为子堆8与子堆12的合并问题。

  5. 同样,在经过一次数值上的比较之后,我们确认应该将二者互换名称。也就是说接下来我们应该将12作为 a,而将8作为 b。

  6. 此时 a 的右孩子为空,因此在再接下来的递归层之上,将直接返回节点8,并且将8作为12的右孩子。也就是说在此局部应该是这样。

    请特别注意,在这层能递归返回之前,还有一项非常重要的任务,你还记得吗?

是的,我们需要确认12 满足左倾性,实际上它这个时候恰恰并不满足,因为我们注意到,它当前的左子树为空,当然,只要留意了这个问题,它的解决并不困难,你也应该记得是怎么处理的——没错,令他的左右子堆互换位置,这是为什么我们会得到这样一个局部结构。

  1. 接下来,我们的递归返回到节点15,同样地,在此我们也需要核对这个节点的左倾性。那么此时它的两个孩子 NPL 值各是多少呢?是的,都应该是1。因此左倾性在这个节点上并没有受到破坏。
  2. 因此我们可以继续逆行而上,递归返回至全堆的根,也就是节点17。此时的17是否满足左倾性呢?我们查验一下它的左右孩子 NPL 值各是多少,你也不妨心算一下。没错,左孩子的 NPL 值为1,而右孩子为 2。也就是说此时的节点 17 恰恰违反了左倾性。
  3. 同样地,关键在于发现问题、解决问题并不困难,在这个情况下,我们也只需经过一次兑换,交换17这个节点的左右孩子,在节点17的左右孩子召唤之后,这个数据结构也就从整体上恢复成一个左式堆。

不要忘了,构成这个堆的成员不多不少,恰好都来自于最初待合并的两个子堆。也就是说,我们已经顺利地完成了这样一个合并的任务。

当然,通过这个实例也可以验证我们最初的设计目标:也就是整个的合并过程的确是围绕着右侧链来进行的。因此整个算法的时间复杂度也自然就不超过右侧链的长度,我们此前已经就此做出过界定,也就是说它在渐进意义下绝对不会超过 log(n), 这个结果再好不过了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2069574.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

srm供应商一体化招采系统解决方案,需求功能清单以及源码实现(JAVA)

1. 供应商管理 2. 采购需求管理 3. 采购寻源管理 4. 采购合同管理 5. 采购订单管理 6. 采购协同管理 7. 外部商城采购管理 8. 报表查询管理 9. 系统管理 10. 集成管理 资料获取:本文末个人名片。

在Activity中使用Menu

在Activity中使用Menu 手机毕竟和电脑不同,它的屏幕空间非常有限,因此充分地利用屏幕空间在手机界面设计中就显得非常重要了。如果你的活动中有大量的菜单需要显示,这个时候界面设计就会比较尴尬,因为仅这些菜单就可能占用屏幕将…

构建高效的串行任务执行器:SerialExecutor深度解析

本文主要介绍怎么去实现一个支持串行执行任务的SerialExecutor执行器 摘要 在复杂的异步编程中,有时我们需要确保任务以串行的方式执行,以维护任务间的依赖关系或顺序。SerialExecutor 是一个自定义的执行器,它封装了 Java 的 Executor 接口…

Linux磁盘分区,增加磁盘应用实例,磁盘情况查询

目录 linux磁盘分区机制 原理介绍 示意图 硬盘说明 查看所有设备挂载情况 挂载的经典案例 给虚拟机添加硬盘 分区 删除挂载 永久挂载 磁盘情况查询 查询系统整体磁盘使用情况 查询指定目录的磁盘占用情况 linux磁盘分区机制 原理介绍 载入可以将一个分区和一个目录…

【精选】基于微信小程序的地铁站点查询系统(全网独一无二,阿龙原创设计)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

C#入门篇3

目录 一、练习 二、显示类型转换(强制类型转换) 三、Convert的转换工厂转换 四、算数运算符号之( /--) 五、关系运算符(比较运算) 六、逻辑运算符 七、复合运算符 一、练习 计算半径为5的圆的面积和周…

Windows平台SDKMAN工具使用

为方便jvm生态的软件版本管理,可以使用sdkman工具来安装和管理诸如java、gradle等软件的当前使用版本。尤其是大多数程序员都是在windows平台开发,团队开发通常都需要统一的jvm相关软件的版本。这里给大家演示下windows平台如何安装和使用sdkman来实现这…

普元EOS-自定义SDO代码生成模板

1 前言 普元EOS的数据实体生成SDO接口和实现类的代码,可以通过自定义代码生成模板,实现代码自定义。 2 模板存放位置 模板存放位置如下:安装目录/dropins/eostools/com.primeton.studio.entity.ui-x.x.x.x.jar里面,SDO模版都在/…

揭秘CAAC、AOPA、ALPA、ASFC和UTC无人机执照的差别及实用价值

CAAC、AOPA、ALPA、ASFC和UTC无人机执照各有其独特的差别及实用价值,以下是针对这些执照的详细解析: 一、CAAC无人机执照 颁发机构:中国民用航空局(CAAC) 差别: - 权威性:CAAC无人机执照是目…

Go机器学习框架之火重燃,Google前研究员开源期望媲美Jax的GoMLX

Go作为一门兼具高性能与简洁性的编程语言,近年来在各种领域得到广泛应用。然而,在机器学习领域,Go相比Python、C、Julia等语言,生态仍然较为薄弱。目前的Go机器学习框架无论在功能全面性上,还是在社区生态支持上都难以…

2024升级zblog小程序开源源码/基于uniapp开发的(支持微信小程序、百度小程序、安卓APP)

源码简介: 2024最新zblog多端小程序开源源码,它是基于uniapp开发的,它是针对和支持微信小程序、百度小程序和安卓APP哦!百度百科小程序源码下载。 这个基于uniapp开发的zblog多端小程序开源源码,听说对收录和SEO都有…

Android 添加系统服务的实现

和你一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 一、前言二、编写AIDL文件三、编写Manager类四、 编写系统服务五、 注册系统服务六、注册Manager七、App调用八、添…

设计模式 -- 七大原则(五)-- 开闭原则

1 基本介绍 开闭原则(Open Closed Principle,简称OCP)是编程中最基础、最重要的设计原则 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。 …

伯努利朴素贝叶斯解析:面向初学者的带代码示例的视觉指南

通过二进制简单性释放预测能力,欢迎来到雲闪世界。 添加图片注释,不超过 140 字(可选) 与虚拟分类器的基线方法或基于相似性的 KNN 推理不同,朴素贝叶斯利用了概率论。它结合了每个“线索”(或特征&#xf…

宿舍管理系统设计与分析

第一章 管理信息系统概述 在人类进入21世纪之际,随着社会的组织化程度以及企业生产的社会化程度越来越高,信息作为一种资源已经和材料、能源并称为现代社会化发展的三大支柱之一。管理信息系统是融科学、信息科学、系统工程以及现代通讯技术、计算机技术…

阿里HPN-大型语言模型训练的数据中心网络架构

阿里巴巴HPN:用于大型语言模型训练的数据中心网络 摘要 本文介绍了阿里云用于大型语言模型(LLM)训练的数据中心网络HPN。由于LLM和一般云计算之间的差异(例如,在流量模式和容错性方面),传统的数据中心网络不太适合LLM训练。这就要求我们专门为LLM培训设…

【NetTopologySuite类库】多边形的五种包围盒(AABB、OBB、包围圆、八边形、凸包)

示例 用的是NetTopologySuite1.5.3版本。 var r new WKTReader(); var wkt "polygon((0 0,0 0.5,1 2,5 0,4 -2,3 -1, 0 0))"; var rawGeo r.Read(wkt); var b1 rawGeo.Envelope;//AABB var b2 new MinimumBoundingCircle(rawGeo).GetCircle();//包围圆 var b3…

基于GeoToolKit实现三维断面的绘制研究

GeoToolkit默认自带PillarSurfaceData的三维断面绘制要求断棱(有时叫断柱)必须是单调的,否则组件底层就会自动优化,导致断面出现回弯,相当于出现重叠,无法实现最终的效果。因此,本文主要在之前文章的基础上,拓展了GeoToolKit的三维断面显示功能。本文主要基于GeoToolKi…

计算机毕业设计hadoop+spark+hive漫画推荐系统 动漫视频推荐系统 漫画分析可视化大屏 漫画爬虫 漫画推荐系统 漫画爬虫 知识图谱 大数据

流程:1.DrissionPageSelenium自动爬虫工具采集漫画视频、详情、标签等约200万条漫画数据存入mysql数据库; 2.Mapreduce对采集的动漫数据进行数据清洗、拆分数据项等,转为.csv文件上传hadoop的hdfs集群; 3.hive建库建表导入.csv动漫…

能精准捕捉股价波峰波谷的 Findpeaks

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 在AI对金融产品进行价值分析中,检测波峰波谷具有至关重要的应用意义。投资者可以直接观察股票价格走势图,通过肉眼识别波峰和波谷的位置。这种方法简单易行,但主观性较强,可能受到投资者个人经验…