从零开始的C++(十八)

avl树中insert的模拟实现

avl树特点:

1.是搜索二叉树

2.每个结点的左右子树高度差的绝对值不超过2

inser模拟实现:

	// 右单旋void RotateR(Node* pParent){Node* parent = pParent;Node* pr = parent->_pRight;Node* prl = pr->_pLeft;//记录父节点Node* pp = parent->_pParent;//更新指针parent->_pRight = prl;if(prl)//判断prl是否存在prl->_pParent = parent;pr->_pLeft = parent;parent->_pParent = pr;if (pp == nullptr){//若parent是根节点_pRoot = pr;pr->_pParent = nullptr;}else{   //父节点连接if (pp->_data < parent->_data){pp->_pRight = pr;pr->_pParent = pp;}else{pp->_pLeft = pr;pr->_pParent = pp;}}//更新平衡因子parent->_bf = 0;pr->_bf = 0;}// 左单旋void RotateL(Node* pParent){Node* parent = pParent;Node* pl = parent->_pLeft;Node* plr = pl->_pRight;//记录父节点Node* pp = parent->_pParent;//更新指针parent->_pLeft = plr;if (plr)//判断prl是否存在plr->_pParent = parent;pl->_pRight = parent;parent->_pParent = pl;if (pp == nullptr){//若parent是根节点_pRoot = pl;pl->_pParent = nullptr;}else{   //父节点连接if (pp->_data < parent->_data){pp->_pRight = pl;pl->_pParent = pp;}else{pp->_pLeft = pl;pl->_pParent = pp;}}//更新平衡因子parent->_bf = 0;pl->_bf = 0;}// 右左双旋void RotateRL(Node* pParent){  Node* parent = pParent;Node* pr = parent->_pRight;Node* prl = pr->_pLeft;int bf = prl->_bf;RotateL(pParent->_pRight);RotateR(pParent);//更新平衡因子if (bf == 0){parent->_bf = pr->_bf = prl->_bf = 0;}else{parent->_bf = -1;pr->_bf = prl->_bf = 0;}}// 左右双旋void RotateLR(Node* pParent){Node* parent = pParent;Node* pl= parent->_pLeft;Node* plr = pl->_pRight;int bf = plr->_bf;RotateR(pParent->_pLeft);RotateL(pParent);//更新平衡因子if (bf == 0){parent->_bf = pl->_bf = plr->_bf = 0;}else{parent->_bf = 0;pl->_bf = 1;plr->_bf = 0;}}// 在AVL树中插入值为data的节点bool Insert(const T& data){if (_pRoot == nullptr){_pRoot = new Node(data);return true;}Node* cur = _pRoot;Node* parent = nullptr;//查看插入位置while (cur){if (cur->_data < data){   parent = cur;cur = cur->_pRight;}else if (cur->_data > data){  parent = cur;cur = cur->_pLeft;}else{//有重复值,插入失败return false;}}//此时parent的子树就是存放data的结点if (parent->_data < data){cur = new Node(data);parent->_pRight = cur;cur->_pParent = parent;parent->_bf++;}else{cur = new Node(data);parent->_pLeft = cur;cur->_pParent = parent;parent->_bf--;}//开始旋转while (parent){if (parent->_bf == 0){//代表插入前后高度不变break;}else if (parent->_bf == 1 || parent->_bf == -1){//插入后高度改变,但仍保持平衡条件cur = parent;parent = parent->_pParent;if (parent == nullptr){break;}if (cur == parent->_pLeft){parent->_bf--;}else{parent->_bf++;}}else if (parent->_bf == 2 || parent->_bf == -2){//此时不满足平衡条件,需要旋转//旋转分四种情况//1.右右if(parent->_bf==2&&cur->_bf==1)RotateR(parent);//2。左左else if(parent->_bf == -2 && cur->_bf == -1)RotateL(parent);//3.右左else if(parent->_bf == 2 && cur->_bf == -1)RotateRL(parent);//4.左右else if(parent->_bf == -2 && cur->_bf == 1)RotateLR(parent);//旋转后高度和插入前高度相同,因此结束break;}else{//此时平衡因子异常,发出中断请求assert(false);}}}

对于一个结点的插入,其影响其父节点的平衡因子(_bf)的值,因此每次插入都需要修改其父节点的平衡因子,而父节点的平衡因子的修改又可能会影响父节点的父节点的平衡因子的值,因此可能会出现连锁修改的情况。以下是所有可能的情况:

1.插入结点后父节点的平衡因子的值变为0,在该情况下父节点的高度在插入前后未发生改变,因此不会继续影响父节点的父节点,因此可以直接退出循环。

2.插入结点后父节点的平衡因子的值变为1或-1,在该情况下父节点的高度插入前后发生修改,增加1,此处通过判断父节点是其父节点的左右子树,来影响父节点的父节点的平衡因子,并继续进入循环进行判断。

3。插入后父节点平衡因子变成大于2的情况,此时抛出异常,因为父节点的平衡因子应符合不超过2,即使在插入新节点后,其平衡因子最大只能增加1,最小只能减小1,因此只能变成绝对值小于等于2的情况,不应该出现绝对值大于2的情况。

3.插入结点后父节点平衡因子变成2或-2,此时不在符合平衡因子绝对值不超过2的情况,因此需要对以父节点为根结点的子树进行旋转修改。此时又分成四种情况。

情况1:

对于这种情况,只需要进行一次选择即可,旋转后的结果如下图:

具体实现逻辑就是parent变成其右孩子的左孩子,原本右孩子的左孩子变成parent的右孩子

经过旋转,使得当前的二叉树仍是avl树,其旋转后的高度与插入结点之前的高度一致,因此不需要继续向上修改父节点。

情况2:

此时若只以A为根进行旋转,则旋转后仍有平衡因子为2或-2的情况,因此需要进行两次旋转。为方便理解,上图等价于下图,以下图来分析。

具体思路:先以b为根进行旋转,使得旋转后高度更高的结点在右侧。

然后以A为根进行旋转即可。

经过两次旋转,实现了高度缩减一,且和插入结点之前相比,子树的父节点的平衡因子不用改变,因此也不需要继续进入循环。

对于上述两种情况,存在镜像的情况,对于那两种情况,只需要与对应的将左右旋转、子树旋转等改变即可。

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

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

相关文章

红海营销时代,内容占位的出海品牌更有机会营销占位

#01 品牌出海&#xff1a;内容占位就是品牌营销占位 红海营销时代&#xff0c;内容信息充斥着用户周边。无论线上还是线下&#xff0c;生活工作、休闲娱乐等不同场景内&#xff0c;广告信息均无孔不入。对于用户来说&#xff0c;能记住的品牌或者商品往往寥寥无几。 占位营销…

全网好评!12个网络工程师必备工具!

你们好&#xff0c;我的网工朋友。 今天来一期久违的工具推荐。工欲善其事必先利其器&#xff0c;好的工具势必会让网工们如虎添翼。 快速掌握正确的工具&#xff0c;意味着你可以轻松地完成复杂的工作。 但市面上的软件太多了&#xff0c;到底选用哪个工具&#xff0c;这还…

【最新Tomcat】IntelliJ IDEA通用配置Tomcat教程(超详细)

前言 IntelliJ IDEA是一个强大的集成开发环境&#xff0c;能够大大简化Java应用程序的开发和部署过程。而Tomcat作为一个流行的Java Web服务器&#xff0c;其与IntelliJ IDEA的整合能够提供便捷的开发环境&#xff0c;让开发人员更专注于代码的创作与优化。 在配置IntelliJ IDE…

linux在非联网、无网络环境下,使用yumdownload、reportrack方法安装rpm包

文章目录 前言1、下载yum-utils​​2、yumdownloader3、repotrack4、安装5、yumdownloader和repotrack的区别总结 前言 当开发者在联网环境下使用Linux时&#xff0c;可以轻松地通过yum或apt-get安装软件。然而&#xff0c;在公司和企业中&#xff0c;由于安全原因&#xff0c…

执行npm的时候报权限问题的解决方案

我们在执行npm操作的过程中&#xff0c;会出现以下权限问题&#xff0c;解决方案: 管理员身份 运行cmd 切换目录到要执行命令的文件下 再进行npm操作即可

社交媒体驱动的独立站流量增长:YouTube引流技巧

随着互联网的不断发展&#xff0c;视频内容在网上变得越来越受欢迎。YouTube作为世界上最大的视频分享平台之一&#xff0c;成为了吸引流量和观众的理想场所。对于跨境卖家来说&#xff0c;利用YouTube来增加独立站流量是一种有效的策略&#xff0c;可以增加知名度、吸引潜在客…

IDEA创建SpringBoot的多模块项目教程

最近在写一个多模块的SpringBoot项目&#xff0c;基于过程总了一些总结&#xff0c;故把SpringBoot多个模块的项目创建记录下来。 首先&#xff0c;先建立一个父工程&#xff1a; &#xff08;1&#xff09;在IDEA工具栏选择File->New->Project &#xff08;2&#xff0…

hypermesh学习总结(一)

1、hypermesh导入导出 2、hypermesh如何使用拓扑命令&#xff0c;连接多个几何体为一个&#xff1f; 3、hypermesh模式选择 分别有显示动力学模式explicit,标准模式Standard3D(静力学及模态等) 4、检查网格单元质量 5、基本平移旋转显示视角操作 6、更改网格划分最小…

【算法挨揍日记】day28——413. 等差数列划分、978. 最长湍流子数组

413. 等差数列划分 413. 等差数列划分 题目描述&#xff1a; 如果一个数列 至少有三个元素 &#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该数列为等差数列。 例如&#xff0c;[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums…

链动2+1模式:创新营销引领白酒产业新潮流

在当今高度竞争的市场环境中&#xff0c;创新营销模式对于企业的发展至关重要。链动21模式作为一种独特的营销策略&#xff0c;将白酒产品与该模式相结合&#xff0c;充分发挥其优势&#xff0c;通过独特的身份晋升和奖励机制&#xff0c;快速建立销售渠道&#xff0c;提高用户…

【C语言.oj刷题】有序#整型矩阵元素查找##{思路+C源码}

目录 题目信息 题目分析&#xff1a; 法一&#xff1a; 遍历二维数组&#xff08;低效&#xff09; 思路 源码 局限性 法二&#xff1a; 对每一行二分查找&#xff08;有所提效&#xff09; 思路 源码 局限性 法三&#xff1a; 利用一切有利条件使用二分查找 思路 …

由两个独立的高增益运算放大器组成的运放芯片D258,可应用于音频信号处理系统上

D258是由两个独立的高增益运算放大器组成。可以是单电源工作&#xff0c;也可以是双电源工作,电源的电流消耗与电源电压大小无关。应用范围包括变频放大器、DC增益部件和所有常规运算放大电路。 主要特点&#xff1a; ● 可单电源或双电源 工作 ● 在一个封装内的两个经…

vue3项目安装eslint和prettier

【几乎最全/全网最长的 2 万 字】前端工程化完整流程&#xff1a;从头搭到尾&#xff08;vue3 vite qiankun docker tailwindcss iview......&#xff09;_前端工程化流程-CSDN博客 vue3tsvite项目中使用eslintprettierstylelinthusky指南 - 掘金 上面两篇文章相互结合操…

网络工程师网络配置经典例题(五)

1、配置SwitchA的单臂静态BFD特性 [SwitchA] bfd [SwitchA-bfd] quit [SwitchA] bfd 1 bind peer-ip 10.2.2.2 interface vlanif 10 source-ip 10.1.1.1 one-arm-echo [SwitchA-bfd-session-1] discriminator local 1 [SwitchA-bfd-session-1] min-echo-rx-interval 200 …

解决:Error: Missing binding xxxxx\node_modules\node-sass\vendor\win32-x64-83\

一、具体报错 二、报错原因 这个错误是由于缺少 node-sass 模块的绑定文件引起的。 三、导致原因 3.1、环境发生了变化 3.2、安装过程出现问题 四、解决方法步骤&#xff1a; 4.1、重新构建 node-sass 模块 npm rebuild node-sass 4.2、清除缓存并重新安装依赖 npm c…

20231117在ubuntu20.04下使用ZIP命令压缩文件夹

20231117在ubuntu20.04下使用ZIP命令压缩文件夹 2023/11/17 17:01 百度搜索&#xff1a;Ubuntu zip 压缩 https://blog.51cto.com/u_64214/7641253 Ubuntu压缩文件夹zip命令 原创 chenglei1208 2023-09-28 17:21:58博主文章分类&#xff1a;LINUX 小工具 文章标签命令行压缩包U…

Google身份验证器Google Authenticator的java服务端实现

Google身份验证器Google Authenticator是谷歌推出的一款基于时间与哈希的一次性密码算法的两步验证软件令牌&#xff0c;此软件用于Google的认证服务。此项服务所使用的算法已列于RFC 6238和RFC 4226中。谷歌验证器上的动态密码按照时间或使用次数不断动态变化&#xff08;默认…

从CentOS向KeyarchOS操作系统的wordpress应用迁移实战

文章目录 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战一、使用浪潮信息X2Keyarch迁移工具完成操作系统的迁移1.1 迁移前的验证1.2 执行迁移评估1.3 开始迁移1.4 验证迁移结果1.5 迁移后的验证 二、总结 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战 CentOS是一…

Element UI 偶发性图标乱码问题

1. 问题如图所示 2. 原因&#xff1a;sass版本低 sass: 1.26.8 sass-loader: 8.0.2 3. 解决方法 (1) 提高sass版本 (2) 在vue.config.js中添加配置 css: {loaderOptions: {sass: {sassOptions: {outputStyle: expanded}}}},4. 遇到的问题 升级后打包&#xff0c;报错 Syntax…

CTFhub-RCE-过滤cat

查看当前目录&#xff1a;输入:127.0.0.1|ls 127.0.0.1|cat flag_42211411527984.php 无输出内容 使用单引号绕过 127.0.0.1|cat flag_42211411527984.php|base 64 使用双引号绕过 127.0.0.1|c""at flag_42211411527984.php|base64 使用特殊变量绕过 127.0.0.…