从零开始的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为根进行旋转即可。

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring boot项目未将resource目录标志为资源目录导致配置文件无效因而运行报错问题

能编译&#xff0c;但不能运行。感觉配置文件没有生效。 将程序代码发给同事&#xff0c;我自己能跑&#xff0c;他不能跑&#xff0c;提示无法构造redis对象。redis的链接写在配置文件里&#xff0c;其实是可以连接的。然后从GIT库下载代码&#xff0c;也同样不能跑。同事的操…

CV计算机视觉每日开源代码Paper with code速览-2023.11.16

点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构】ConvNet vs Transformer, Supervised vs CLIP: Beyond ImageNet Accuracy 论文地址&#xff1a;https://arxiv.org//pdf/23…

VBA技术资料MF85:将工作簿批量另存为PDF文件

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

基于SSM的社区生鲜商城的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

【探索嵌入式虚拟化技术与应用】— 虚拟化技术深入浅出自学系列

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏:【探索嵌入式虚拟化技术与应用】&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 一、虚拟技术的发展历史 1.1传统技术的局限性&#xff1a; ​编辑 1.2云计算和万物互联技术的发展机遇&#x…

Altium Designer学习笔记6

原理图库的制作&#xff0c;SMA元件的制作&#xff1a; 图形不是很重要&#xff0c;重要的是管脚的功能。 Design Item ID和Designator两个值是要注意的。 进行Place放置&#xff0c;切换到原理图工作区&#xff0c;测试下功能。 AD9851元件库制作&#xff1a; 不需要再新建原…

UE4 基础篇十四:自定义插件

文末有视频地址和git地址 一、概念 虚幻里插件都是用C++写的,C++包括.h文件和.cpp文件,.h头文件通常包含函数类型和函数声明,cpp文件包含这些类型和函数的实现, 你为项目编写的所有代码文件都必须位于模块中,模块就是硬盘里的一个文件夹,包含名为“Build.cs”的C#文件…

股票指标信息(六)

6-指标信息 文章目录 6-指标信息一. 展示股票的K线图数据,用于数据统计二. 展示股票指标数据,使用Java处理,集合形式展示三. 展示股票目前的最新的指标数据信息四. 展示股票指标数据,某一个属性使用Java处理五. 展示股票的指标数据,用于 Echarts 页面数据统计六. 展示股票指标数…

企业软件定制开发的重点是什么?|app小程序网站建设

企业软件定制开发的重点是什么&#xff1f;|app小程序网站建设 企业软件定制开发的重点是满足企业的独特需求&#xff0c;提供高效、灵活、可靠的解决方案。随着企业信息化程度的不断提升&#xff0c;越来越多的企业开始意识到传统的软件产品无法完全满足其实际需求&#xff0c…

安全领航,共筑敏捷开发新时代【云驻共创】

安全领航&#xff0c;共筑敏捷开发新时代。网络安全形势虽然严峻&#xff0c;但得益于企业安全意识的提升&#xff0c;近两年来遭受网络攻击的网站不断减少&#xff0c;普通网民的个人隐私及其他敏感数据得到了更多的保证。华为云基于自身多年的安全经验研发了可以帮助开发者实…

板块概念相关(五)

5-板块概念相关 文章目录 5-板块概念相关一. 查询所有的版块列表二. 查询所有的概念列表三. 查询所有的地域列表四. 查询所有的版块资金支持的类型五. 查询某个版块历史记录列表,形成图表形式六. 查询某个版块历史记录列表七. 查询某个版块今日资金,形成图表形式八. 查询该板块…

Java精品项目源码基于SpringBoot的樱花短视频平台(v66)

Java精品项目源码基于SpringBoot的樱花短视频平台(v66) 大家好&#xff0c;小辰今天给大家介绍一个樱花短视频平台&#xff0c;演示视频公众号&#xff08;小辰哥的Java&#xff09;对号查询观看即可 文章目录 Java精品项目源码基于SpringBoot的樱花短视频平台(v66)难度指数&…

MAX/MSP SDK学习05:A_GIMME方法

今天终于将A_GIMME方法部分的描述看懂了&#xff0c;上周因为太赶时间加上这文档很抽象一直没看懂。也就那么一回事&#xff0c;记录一下。 A_GIMME方法用于接收多个参数&#xff1a; #include "ext.h" // standard Max include, always required #include "…

git修改commit历史提交时间、作者

1、修改最近的几条记录&#xff0c;进入提交记录列表&#xff0c;修改提交记录模式 git rebase -i HEAD~3 // 修改最近的三条记录&#xff0c;顺序排列按提交时间升序 指令说明&#xff1a; pick&#xff1a;保留该commit&#xff08;缩写:p&#xff09; reword&#xff1a…

C语言进制转换(1112:进制转换(函数专题))

题目描述 输入一个十进制整数n&#xff0c;输出对应的二进制整数。常用的转换方法为“除2取余&#xff0c;倒序排列”。将一个十进制数除以2&#xff0c;得到余数和商&#xff0c;将得到的商再除以2&#xff0c;依次类推&#xff0c;直到商等于0为止&#xff0c;倒取除得的余数…

Windows + Syslog-ng 发送eventlog 到Splunk indexer

1: 背景: 装了window Splunk universal forwarder 的 window server 要把event log 送到linux 的splunk indexer 上,由于网络的原因,不能直接发送数据到splunk indexer的话,要利用跳板机来实现: 2:架构: 3: 先说明每个类型server 上的安装情况: Window server: 安装S…

鸿蒙系统扫盲(二):再谈鸿蒙是不是安卓套壳?

最近小米发布了澎湃OS&#xff0c;vivo发布了蓝OS&#xff0c;好像自从华为回归后&#xff0c;大伙都开始写自己的OS了&#xff0c;小米官方承认是套壳安卓&#xff0c;然后被大家喷了&#xff0c;于是鸿蒙是不是安卓套壳的话题又回到了大众的视野&#xff0c;今天在讨论下这个…

Delayed 延时任务

延时任务与定时任务的区别 延时任务&#xff0c;可以理解为定时任务的一种&#xff0c;但是他们是有区别的。 延时任务&#xff1a;将程序代码延时执行&#xff0c;执行完毕&#xff0c;即为结束。 定时任务&#xff1a;周期性执行任务。代码执行完毕后&#xff0c;并不意味着…

基于单片机仓库温湿度监测报警系统仿真设计

**单片机设计介绍&#xff0c;基于单片机仓库温湿度监测报警系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的仓库温湿度监测报警系统可以被设计成能够实时监测仓库内的温度和湿度&#xff0c;并根据预设…

pytest-base-url插件之配置可选的项目系统URL

前言 ①当我们的自动化代码完成之后&#xff0c;通常期望可以在不同的环境进行测试&#xff0c;此时可以将项目系统的URL单独拿出来&#xff0c;并且可以通过pytest.ini配置文件和支持pytest命令行方式执行。 ② pytest-base-url 是一个简单的pytest插件&#xff0c;它通过命…