数据结构(邓俊辉)学习笔记】优先级队列 04——完全二叉堆:插入与上滤

news2024/12/29 10:25:25

文章目录

  • 1. 上滤
  • 2. 实例
  • 3. 实现
  • 4. 效率

1. 上滤

好,接下来我们就来学习在一个完全二叉堆中,如何有效地插入一个新的元素。我们将会看到插入过程中的核心技巧是所谓的 ”上滤“ 过程。
在这里插入图片描述

为了在完全二叉堆中引入一个新的词条 e,我们只需在物理上将它作为末元素,直接插入至对应的向量之中。没错,向量。

请记住,尽管在逻辑上我们可以将优先级队列理解为一棵完全二叉树,但在物理上它依旧是一个不折不扣的向量,向量在物理上增加一个末元素,等效于在这棵完全二叉树底层向空缺的部分拓展一个节点。

可以看到,将新的词条作为末元素接入向量的好处在于,可以使得完全二叉堆的结构性得以延续。当然,另一条件,也就是堆序性如果也能够得以延续,那么我们也就大功告成。然而很遗憾,在新的节点引入之后,堆序性未必能够延续。

当然,即便如此,情况也不致太糟糕。具体来说,唯一可能违背堆序性的只有新插入的这个节点与它的父亲。也就是说,新插入的这个节点拥有一个父亲,而且在数值上,新插入的这个节点要大于它的父亲。

既然找到了问题的症结,我们也就自然得到了解决的办法。没错,在这种情况下我们只需将新插入的节点 e 与它的父亲互换位置,从而转换为这样一种状态。不难看出经过这样的转换之后,不仅顺利地解决了 节点e 与它此前的父亲之间的逆序性,同时其他所有节点之间的堆序性也不致受到影响。当然,问题未必就此完全地解决。

因为 e 有可能依然会有一个新的父亲。而且如果不巧,e 有可能依然会大于这个新的父亲,也就是说,e 和它新的父亲再次违反堆序性。你应该知道如何解决这个问题了。是的,我们只需再次套用此前的策略,令 e 和它新的父亲互换位置,从而进入这样一种状态。同样经过这样一次交换,在刚才这一层的逆序性得到了修复,而且同时不致影响到其他的节点。接下来如果依然存在问题,也只可能是 e 和它这个最新的父亲违背堆序性。果真如此,我们可以继续令e和它的父亲互换位置,从而转入这样一种状态。

好消息是,这样一个反复交换的过程,满足某种单调性。 不难看出,每经过这样一次交换,e 的高度就会上升一层,同时违反堆序性的情形如果存在,也必然会上升一层。这一过程,亦即所谓的上滤(percolate up)

既然这样一个逐层调整的过程充其量不过抵达到树根,因此也迟早会终止于某个位置。而一旦这个过程终止,也就意味着堆序性在整个完全二叉堆中得到了彻底的恢复。

2. 实例

在这里插入图片描述
注意:上图所标注的数值都是元素的优先级而非其所对应的秩。

我们来看一个简单的实例,不难验证,这是一个由5个词条所构成的完全二叉堆。上面的这棵完全二叉树是它的逻辑结构,而下面则是其在物理上对应的向量结构。

  1. 可以看到在物理上向量的首元素也就是逻辑上完全二叉树的根节点。根据我们的约定,它正是整个数据集中的最大者。
  2. 接下来,假设我们需要插入一个数值为 5 的词条。按照刚才所涉及的算法,我们首先将它作为末元素加入到向量之中,在逻辑上这完全等效于在完全二叉树的底层向右侧拓展了一个节点。可以看到,这种拓展的确没有破坏完全二叉堆的结构性。然而正如这个例子中的情况,新引入的这个词条有可能和它的父亲违背堆序性,因为5大于0。于是按照我们刚才所拟定的策略,令二者互换位置。请注意,这一兑换物理上实际上是在向量之中进行的。
  3. 经过交换之后的结果是这样(上图3),可以看到局部的堆序性的确得到了恢复,同时也不致于影响到其他的各个节点。然而新插入的这个节点上升一层之后,有可能会有一个新的父亲,比如这里的4。而且很不幸,因为5依然大于4,所以我们说在这个局部同样违反了堆序性。好在不要紧,因为我们可以继续沿用刚才拟定的策略,并违反堆序性的两个节点互换位置。同样在物理上,这种交换也是在向量内部进行的。
  4. 经过这次交换之后,的确4和5 互换了位置,新插入的节点5继续上升一层,这一局部的堆序性得到了恢复,而且同样不致影响到其它的节点。而新插入的这个节点5在上升了一层以后,已经悄然间成为了这个堆的堆顶。它根本就没有父亲,因此堆序性在这一局部也就自然成立。更重要的是,至此堆续性在整个完全二叉堆中处处得到满足。

我们也就顺利地完成了这次插入操作。可以看到,整个插入算法的实质过程,无非是令新引入的这个节点不断地与它的父亲交换位置。每交换一次,新引入的这个节点都会上升一层。那么这样一个过程如何兑现为具体的代码呢?

3. 实现

在这里插入图片描述

在这里我们给出完全二叉堆插入算法的一种可行实现方式:

  1. 首先,将待插入的词条接入向量之中,为此我们所借用的是向量的插入接口。你应该记得,在默认的情况下,这个接口会将新元素作为末元素插入其中。既然是末元素,新插入这个词条在向量中对应的秩就应该是 n - 1。
  2. 因此接下来我们可以调用 percolateUp 算法完成对这个新节点的上滤调整。
  3. percolateUp 算法可以实现如下:
    (1) 迭代式的上滤调整过程是以while 循环来实现的。如果当前词条的秩为 i,我首先要检查它的父亲是否存在。也就是说 i 是否已经成为堆顶。 倘若词条 i 的确成为了堆顶,这个循环就会立即退出,算法也随即终止。
    (2)不失一般性,如果 i 的父亲存在,我们就记为 j。
    (3)接下来通过依次比对,我们就可以判断出这对父子节点是否逆序。一旦它们不再逆序,这个循环也会随即退出。
    (4)否则如果的确在这个位置违反堆序性,我们就按照刚才的算法将两个元素互换位置,同时更新节点的秩,也为下一步迭代做好准备。

这个算法的正确性不难验证。那么接下来的问题便是这个算法需要运行多长时间呢?对应的时间复杂度是否能达到我们所预期的目标呢?

4. 效率

在这里插入图片描述
应该记得,在完全二叉堆中插入新元素之后的调整过程之所以称作是”上滤“,是因为每经过一步迭代,新插入元素的位置都会上升一次。换而言之,整个算法在完全二叉堆的每一层次上至多只需做一步迭代。

我们知道完全二叉树是理想平衡的二叉树,其树高可以严格地控制在 log( n) 的范围内。我们刚才也已看到,每一步迭代只需常数的时间。因此所有的迭代所需的时间累计也不过log( n) 。

就渐进的意义而言,这已经实现了我们最初的设计目标。当然就常系数的意义而言,这里依然还有改进的余地。你应该记得,在我们刚才所给出的实现中,每一次交换都是通过一个名为 swap 的过程来完成。这样的一次操作通常都意味着三次赋值操作,因此在最坏情况下,我们累计需要做多达 3*log( n) 赋值。

针对这一问题,一种简明的改进方法就是,首先将新插入的词条做备份,每次如有必要交换,我们只是下移它的父节点。直到能够确定 e 已经无需继续上滤时,我们才将此前备份的这个词条纳入于最终的这个位置。 如此我们就可将赋值操作的次数从 3*log( n) 减至 log( n) + 2,从而在常系数意义上有所改进。

当然,另一类操作,也就是父子词条之间的大小比较操作也可以有一定的改进。

关于完全二叉堆,另一个好消息是它的平均性能要远远优于刚才所分析的最坏情况。 实际上,新插入节点需要持续上升足够多层,乃至最终能够抵达树根的情况,出现的可能性是极低的。更加精细的估算表明,在通常的随机分布下,每个节点上升的平均高度实际上只不过是常数。这也是完全二叉堆低成本、高效率的重要证据。

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

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

相关文章

【网络编程】TCP实现网络通信(C语言、Ubuntu实现)

TCP服务器通信模型:(分为以下6个步骤) 1、sfd socket(); //创建一个用于连接的套接字文件描述符 2、bind(); //为服务器套接字绑定ip地址和端口号,为了让客户端额能够找到服务器 3、l…

C++第三十七弹---深入理解红黑树:旋转、着色与性质维护

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】 目录 1 红黑树 1.1 红黑树的概念 1.2 红黑树的性质 1.3 红黑树节点的定义 1.4 红黑树结构 1.5 红黑树的插入操作 1.6 红黑树的验证 1.7 红黑树与…

XSS的一些相关案例及DOM破坏的案例

目录 第一关 第二关 第三关 第四关 第五关 第六关 第七关 第八关(DOM破坏) 网址:XSS Game - Learning XSS Made Simple! | Created by PwnFunction 第一关 来分析一下代码 就是一个URL类里进行一个get接收参数(somebody)如果没参数就默认接收(Somebody)这…

C++仿C#实现事件处理

测试 #include "beacon/beacon.hpp" #include <cstdio> #include <thread>class mouseEvent : public beacon::args { public:mouseEvent(int x, int y) : x(x), y(y) {}int x, y; };class object : public beacon::sender { public:};class mouseHandl…

6大企业必备的公司常用的加密软件推荐|2024公司常用加密软件推荐!

2024年上半年&#xff0c;企业对于数据加密的需求日益增长&#xff0c;以确保数据在存储和传输过程中的安全性。以下是六款企业常用的加密软件推荐&#xff0c;它们各具特色&#xff0c;能够满足不同企业的加密需求&#xff1a; 1.NordLocker&#xff1a; 特点&#xff1a;它是…

【Linux系列】telnet使用入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

什么是视频比特率?与视频时长是什么关系

​ ‌比特率是指单位时间内传输或处理的比特的数量&#xff0c;单位为‌bps(‌bit per second)。‌ 比特率经常用于描述在电信和计算领域中数据传输的速度&#xff0c;也可以作为衡量音频和视频文件数据率的指标。比特率越高&#xff0c;传送的数据越大&#xff0c;音频或视频…

Ubuntu安装Anaconda3

本文详细阐述了在 Ubuntu 系统中安装 Anaconda3 的完整流程。包括 Anaconda3 安装包的获取途径&#xff0c;具体安装过程中的每一个步骤及注意事项&#xff0c;还有安装后的环境变量设置和安装成功的验证方法。旨在为 Ubuntu 用户提供清晰、易懂且准确的 Anaconda3 安装指南&am…

Windows Microsoft Edge 浏览器 配置【密码】

在浏览 Web 时&#xff0c;Microsoft Edge 可以轻松保存密码。 在桌面或移动设备上的 Edge 浏览器中输入新密码时&#xff0c;Microsoft Edge 会询问你是否要记住用户名和密码。 下次访问该网站时&#xff0c;浏览器将完成帐户信息的填写。 如果使用 Microsoft 帐户登录到 Edg…

重塑业务生态,Vatee万腾平台:引领行业变革的新引擎

在数字经济浪潮汹涌的今天&#xff0c;传统行业的边界正被不断模糊与重塑&#xff0c;新兴技术如云计算、大数据、人工智能等正以前所未有的速度改变着商业世界的面貌。在这一背景下&#xff0c;Vatee万腾平台应运而生&#xff0c;以其独特的创新模式和强大的技术实力&#xff…

i.MX6裸机开发(1):环境搭建

1. 熟悉sdk SDK&#xff08;Software Development Kit&#xff09;是NXP针对其官方评估 版的软件开发包&#xff0c;可以在NXP的官网下载得到。SDK中包含了 各种程序范例&#xff0c;我们心心念念的固件库也包含在它里边。 NXP官网链接&#xff1a;https://www.nxp.com 未登录…

Camera基础知识系列(2)——对焦和变焦

目录 一. 引言 二. 对焦 定义&#xff1a; 原理 三. 变焦 定义 用途 四. 总结 一. 引言 这一节简单聊一下对焦和变焦&#xff0c;这两个是摄影种出现的高频词&#xff0c;但这里把它们放一起讲&#xff0c;主要还是因为它们在字面上就一字之差&#xff0c;初次接触…

XSS DOM破坏实战案例

目录 案例一 思考 源码分析 查找问题 实现 案例二 查看源码 问题查找 实现 实验环境&#xff1a;DOM clobbering | Web Security Academy (portswigger.net) 案例一 里面是一篇篇的博客&#xff0c;点击进去里面是一些评论 思考 尝试一些常规的xss 没什么效果... 他将…

Java、python、php版的企业单位考勤打卡管理系统的设计与实现(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

无人机之螺旋桨的安装与维护

一、安装&#xff1a;正确安装桨叶至关重要。请确保顺时针旋转的桨叶安装在对应的电机上&#xff0c;并使逆时针旋转的桨叶安装在相应的电机上。否则&#xff0c;无人机可能无法正常飞行或失去控制。 二、维护&#xff1a;为了确保无人机的安全及长久使用&#xff0c;请定期检…

pytorch-AutoEncoders

目录 1. 监督学习&无监督学习1.1 监督学习1.2 无监督学习1.3 为什么需要无监督学习 2. AutoEncoders3. Auto Encoders loss function4. PCA VS Auto Encoders5. Auto Encoders的变种5.1 Denoising Auto Encoders5.2 Dropout AutoEncoders5.3 Adversarial AutoEncoders5.4 V…

使用 Python构建 Windows 进程管理器应用程序

在这篇博客中&#xff0c;我们将探讨如何使用 wxPython 构建一个简单的 Windows 进程管理器应用程序。这个应用程序允许用户列出当前系统上的所有进程&#xff0c;选择和终止进程&#xff0c;并将特定进程保存到文件中以供将来加载。 C:\pythoncode\new\manageprocess.py 全部…

打击盗版,禁止盗版软件联网!电脑下载了不安全的“软件”,怎么禁止它联网?这三种方法最常用!

数字化时代&#xff0c;盗版软件的泛滥不仅侵犯了软件开发者的知识产权&#xff0c;还严重威胁到用户的网络安全和数据安全。当不慎在电脑上下载了不安全的盗版软件时&#xff0c;如何有效地禁止其联网&#xff0c;成为保护个人或企业信息、系统安全的重要一环。 本文将为您介…

Qt框架学习04——元对象系统

元对象系统&#xff09; 1. RTTI 概念2. 元对象系统2.1 元对象的概念2. 2 使用元对象系统获取类信息 总结&#xff1a; 1. RTTI 概念 Runtime Type Identification运行时类型识别typeid() 2. 元对象系统 2.1 元对象的概念 用来记录类的原始信息的对象称之为元对象用于继承于…

LLMs之Leaderboard:Gorilla的简介、安装和使用方法、案例应用之详细攻略

LLMs之Leaderboard&#xff1a;Gorilla的简介、安装和使用方法、案例应用之详细攻略 导读&#xff1a;2023 年5月 24 日&#xff0c;UC伯克利等发布Gorilla。该工作针对LLM有效调用API工具的问题&#xff0c;提出了一种检索式微调语言模型的新方法Gorilla&#xff0c;并构建了相…