从零开始的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.rhkb.cn/news/200353.html

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

相关文章

【设计模式】结构型设计模式

结构型设计模式 文章目录 结构型设计模式一、概述二、适配器模式&#xff08;Adapter Pattern&#xff09;2.1 类适配器模式2.2 对象适配器模式2.3 接口适配器模式2.4 小结 三、桥接模式&#xff08;Bridge Pattern&#xff09;四、装饰器模式&#xff08;Decorator Pattern&am…

2 Redis的高级数据结构

1、Bitmaps 首先&#xff0c;最经典的应用场景就是用户日活的统计&#xff0c;比如说签到等。 字段串&#xff1a;“dbydc”&#xff0c;根据对应的ASCII表&#xff0c;最后可以得到对应的二进制&#xff0c;如图所示 一个字符占8位&#xff08;bit&#xff09;&#xff0c;…

操作系统基础操作

操作系统的启动 体系结构概念 CPU、I/O、内存-通过总线连接 操作系统一开始存放时没有放在内存里&#xff0c;而是当在DISK中&#xff0c;由BIOS提供相应支持 DISK&#xff1a;存放OSBIOS&#xff1a;基本I/O处理系统&#xff08;计算机开机时可以让系统检测各种外设&#…

idea 环境搭建及运行java后端源码

1、 idea 历史版本下载及安装 建议下载和我一样的版本&#xff0c;2020.3 https://www.jetbrains.com/idea/download/other.html&#xff0c;idea分为专业版本&#xff08;Ultimate&#xff09;和社区版本&#xff08;Community&#xff09;&#xff0c;前期可以下载专业版本…

“开源 vs. 闭源:大模型的未来发展趋势预测“——探讨大模型未来的发展方向

文章目录 每日一句正能量前言什么是大模型的开源与闭源开源与闭源的定义和特点开源的意义开源和闭源的优劣势比较不同的大模型企业&#xff0c;开源、闭源的策略不尽相同。企业在开发垂类模型时选择开源还是闭源大模型开源vs 闭源&#xff1a;两者并非选择题后记 每日一句正能量…

多模态大模型训练数据集汇总介绍

RefCOCO、RefCOCO、RefCOCOg 这三个是从MS-COCO中选取图像得到的数据集&#xff0c;数据集中对所有的 phrase 都有 bbox 的标注。 RefCOCO 共有19,994幅图像&#xff0c;包含142,209个引用表达式&#xff0c;包含50,000个对象实例。RefCOCO 共有19,992幅图像&#xff0c;包含1…

【开源】基于Vue和SpringBoot的中小学教师课程排课系统

项目编号&#xff1a; S 053 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S053&#xff0c;文末获取源码。} 项目编号&#xff1a;S053&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 角色管理模块2.2 课程档案模块2.3 排…

【前端学java】Java中的异常处理(15)完结

往期回顾&#xff1a; 【前端学java】JAVA开发的依赖安装与环境配置 &#xff08;0&#xff09;【前端学java】java的基础语法&#xff08;1&#xff09;【前端学java】JAVA中的packge与import&#xff08;2&#xff09;【前端学java】面向对象编程基础-类的使用 &#xff08;…

STM32:时钟树原理概要

在一般情况下只要在CubeIDE中将RCC下的高速时钟源设置成晶振&#xff0c;随后在时钟配置中把HCLK设置到最大频率&#xff08;比如STM32F103的最高频率是72MHZ &#xff09;&#xff0c;CubeIDE就会帮我们自动调节其它参数到合适的值。这样我们芯片就可以全速运行了。 一、时钟信…

C++函数

转载知呼大佬06 - C函数 - 知乎 (zhihu.com) 06 - C函数 本期我们讨论的是 C 中的函数。 函数到底是什么呢&#xff0c;函数就是我们写的代码块&#xff0c;被设计用来执行特定的任务&#xff0c;以后我们学习 class 类的时候&#xff0c;这些块会被称为方法&#xff0c;但是…

windows排除扫描文件夹

搜索防火墙和网络保护 点击病毒和威胁防护 往下拉&#xff0c;找到排除项 添加排除项

MySQL InnoDB 引擎底层解析(三)

6.3.3. InnoDB 的内存结构总结 InnoDB 的内存结构和磁盘存储结构图总结如下&#xff1a; 其中的 Insert/Change Buffer 主要是用于对二级索引的写入优化&#xff0c;Undo 空间则是 undo 日志一般放在系统表空间&#xff0c;但是通过参数配置后&#xff0c;也可以用独立表空 间…

【C++上层应用】2. 预处理器

文章目录 【 1. #define 预处理 】【 2. #ifdef、#if 条件编译 】2.1 #ifdef2.2 #if2.3 实例 【 3. # 和 ## 预处理 】3.1 # 替换预处理3.2 ## 连接预处理 【 4. 预定义宏 】 预处理器是一些指令&#xff0c;指示编译器在实际编译之前所需完成的预处理。 所有的预处理器指令都是…

分类预测 | Matlab实现基于PSO-SDAE粒子群优化算法优化堆叠去噪自编码器的数据分类预测

分类预测 | Matlab实现基于PSO-SDAE粒子群优化算法优化堆叠去噪自编码器的数据分类预测 目录 分类预测 | Matlab实现基于PSO-SDAE粒子群优化算法优化堆叠去噪自编码器的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现基于PSO-SDAE粒子群优化算法…

Flutter笔记:使用相机

Flutter笔记 使用相机 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/134493373 【简介】本文介绍在 Fl…

听GPT 讲Rust源代码--src/librustdoc

题图来自 Why is building a UI in Rust so hard? File: rust/src/librustdoc/core.rs 在Rust中&#xff0c;rust/src/librustdoc/core.rs文件的作用是实现了Rustdoc库的核心功能和数据结构。Rustdoc是一个用于生成Rust文档的工具&#xff0c;它分析Rust源代码&#xff0c;并生…

git基本操作(配图超详细讲解)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 创建git本地仓库 配置仓库 认识工作区&#xff0c;暂存区&#xff0c;版本库 修改文件 版本回退 撤销修改 删除文件 创建git本地仓库 要提前说的是&#xff0c;仓库是进⾏版本控制的⼀个⽂件⽬录。我们要想对⽂…

linux网络——HTTPS加密原理

目录 一.HTTPS概述 二.概念准备 三.为什么要加密 四.常⻅的加密⽅式 1.对称加密 2.⾮对称加密 五.数据摘要&#xff0c;数字签名 六.HTTPS的加密过程探究 1.方案一——只使用对称加密 2.方案二——只使⽤⾮对称加密 3.方案三——双⽅都使⽤⾮对称加密 4.方案四——⾮…

stack和queue简单实现(容器适配器)

容器适配器 stack介绍stack模拟实现queue 介绍queue模拟实现deque stack介绍 stack模拟实现 以前我们实现stack&#xff0c;需要像list,vector一样手动创建成员函数&#xff0c;成员变量。但是stack作为容器适配器&#xff0c;我们有更简单的方法来实现它。 可以利用模板的强大…

go语言学习之旅之Go 语言指针

学无止境&#xff0c;今天继续学习go语言的基础内容 Go语言支持指针&#xff0c;允许你在程序中直接操作变量的内存地址。指针存储了变量的内存地址&#xff0c;通过指针&#xff0c;你可以直接访问或修改该地址上的值。 学习过c语言的一定知道指针 定义指针 在Go语言中&…