C++进阶之AVL树

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶     C++进阶​    ​​​​算法

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.前言

二.插入

三.旋转 

3.1右旋

3.2左旋

3.3左右双旋

3.4右左双旋

四.测试


一.前言

        在看这篇博客之前需要了解二叉搜索树的相关内容,可以看这篇博客二叉搜索树,AVL树可以看成为了解决二叉搜索树的问题,它保证了左右子树高度差不超过1。本次的内容的重点就是对AVL树的旋转。

二.插入

        AVL树的插入规则和二叉搜索树的插入规则类似,左子树都小于父节点,右子树都大于父节点,在这里我们引入了一个平衡因子,我们先插入后然后进行调节平衡因子,平衡因子的计算=右子树的高度-左子树的高度,插入的新节点的平衡因子为0,当插入的节点在父节点的右边,父节点的平衡因子+1,当插入的节点在父节点的左边,父节点的平衡因子-1,当整后父节点的平衡因子为0时直接结束,不需要继续调整,当调整后父节点的平衡因子为+1或者-1时需要继续向上进行调整,当调整后父节点的平衡因子为+2或-2时需要进行旋转。我们看下面的代码实现:

bool insert(const pair<K, V>& kv)
{
	Node* newnode = new Node(kv);
	if (_root == nullptr) _root = newnode;
	else
	{
		Node* cur = _root, * parent = nullptr;
		while (cur)
		{
			if (kv.first < cur->_kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (kv.first > cur->_kv.first) 
			{
				parent = cur;
				cur = cur->_right;
			}
			else  return false;
		}
		if (kv.first < parent->_kv.first) parent->_left = newnode;
		else parent->_right = newnode;
		newnode->_parent = parent;

		//调整平衡因子

			while (parent)
		{
			if (newnode == parent->_left) parent->_bf--;
			else parent->_bf++;

			if (parent->_bf == 0) break;
			else if (parent->_bf == 1 || parent->_bf == -1)
			{
				newnode = parent;
				parent = parent->_parent;
			}
			else if (parent->_bf == 2 || parent->_bf == -2)
			{
				if (parent->_bf == 2 && newnode->_bf == 1)
				{
					RatoteL(parent);
				}
				else if (parent->_bf == -2 && newnode->_bf == -1)
				{
					RatoteR(parent);
				}
				else if (parent->_bf == 2 && newnode->_bf == -1)
				{
					RatoteRL(parent);
				}
				else if (parent->_bf == -2 && newnode->_bf == 1)
				{
					RatoteLR(parent);
				}
				else
				{
					assert(false);
				}
				break;
			}
			else
			{
				assert(false);
			}

		}

	}
	return true;
}

三.旋转 

        旋转有4种方式:向右旋转,向左旋转,左右双旋,右左双旋这四种

3.1右旋

        看下面的抽象图

 当n=0时全图为

当n=1时全图为

当n=2时我们有3种,但是在a的位置能放第3种,因为别的会自动进行旋转,b和c这三种都可以

  当n=3时就会更多,所以这是列举不完的,针对右旋我们以下面这张图为例:

我们经过右旋后转化成下面的样子,针对的主要就是这几个节点

 

在旋转的过程中需要注意的是,parent节点是不是根节点,注意调整后subL节点的的父节点的调整,还有一点就是subLR是否为空节点,调整后需要将subL节点和parent节点的bf值改为0,我们看下面的代码:

	void RatoteR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		subL->_right = parent;
		parent->_left = subLR;
		Node* ppNode = parent->_parent;
		subL->_parent = parent->_parent;
		parent->_parent = subL;
		if (subLR)
			subLR->_parent = parent;
		if (parent == _root)
		{
			_root = subL;
		}
		else
		{
			if (ppNode->_left == parent)
				ppNode->_left = subL;
			else
				ppNode->_right = subL;
		}
		subL->_bf = parent->_bf = 0;
	}

3.2左旋

        左旋的代码和右旋的类似,不过需要调节的平衡因子为2和1,我们看下面的图片

我们直接上代码:

void RatoteL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;

	parent->_right = subRL;
	if (subRL)
		subRL->_parent = parent;
	Node* ppNode = parent->_parent;
	parent->_parent = subR;
	subR->_left = parent;
	subR->_parent = ppNode;
	

	if (parent == _root)
	{
		_root = subR;
	}
	else
	{
		if (ppNode->_left == parent)
			ppNode->_left = subR;
		else
			ppNode->_right = subR;
	}
	subR->_bf = parent->_bf = 0;
}
void RatoteRL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	int bf = subRL->_bf;

	RatoteR(subR);
	RatoteL(parent);

	if (bf == 1)
	{
		parent->_bf = -1;
	}
	else if (bf == -1)
	{
		subR->_bf = 1;
	}
	
}

3.3左右双旋

        左右双旋的图片可以看为下面的抽象图:

当我们在b位置插入后再旋转,可以得到:

当我们插入到c位置后再经过旋转,可以得到:

 

当只旋转一次就会做一次镜像旋转,我们先让subL节点左旋,然后让parent右旋,然后进行调节平衡因子,我们看代码:

void RatoteLR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	int bf = subLR->_bf;

	RatoteL(subL);
	RatoteR(parent);

	if (bf == 1)
	{
		subL->_bf = -1;
	}
	else if (bf == -1)
	{
		parent->_bf = 1;
	}
}

3.4右左双旋

        这个和左右双旋类似,我们直接看代码:

	void RatoteRL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;
		int bf = subRL->_bf;

		RatoteR(subR);
		RatoteL(parent);

		if (bf == 1)
		{
			parent->_bf = -1;
		}
		else if (bf == -1)
		{
			subR->_bf = 1;
		}
		
	}

四.测试

        我们直接上代码:

public:	
    void InOrder()
	{
		_InOrder(_root);
	}

	bool IsBalance()
	{
		return _IsBalance(_root);
	}
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;
		_InOrder(root->_left);
		cout << root->_kv.first << "->" << root->_kv.second << endl;

		int left = _height(root->_left);
		int right = _height(root->_right);
		int sub = abs(left - right);
		cout << "bf-> " << sub<<endl;
		if (sub >= 2) 
			cout<<"key-> "<< root->_kv.first << endl;
		_InOrder(root->_right);
	}
	int _height(Node* root)
	{
		if (root == nullptr)
			return 0;
		int x = 1 + _height(root->_left);
		int y = 1 + _height(root->_right);

		return max(x , y);
	}
	bool _IsBalance(Node* root)
	{		
		if (root == nullptr) return true;
		int left = _height(root->_left);
		int right = _height(root->_right);

		if (abs(right - left) >= 2)
		{
			return false;
		}
		return _IsBalance(root->_left) && _IsBalance(root->_right);

	}

测试代码:

int main()
{
	srand(0);
	AVLTree<int, int> a;
	vector<int> v;
	for (int i = 0; i < 1000000; i++)
	{
		int num = rand() + i;
		v.push_back(num);
	}


	cout << a.IsBalance() << endl;
	return 0;
}

运行可以看到:

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

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

相关文章

postman国内外竞争者及使用详解分析

一、postman简介 Postman 是一款广泛使用的 API 开发和测试工具&#xff0c;适用于开发人员和测试人员。它提供了一个直观的界面&#xff0c;用于发送 HTTP 请求、查看响应、创建和管理 API 测试用例&#xff0c;以及自动化 API 测试工作流程。以下是 Postman 的主要功能和特点…

Docker常用操作和命令

文章目录 1、卸载旧版本 2、yum安装Docker CE&#xff08;社区版&#xff09; 3、添加镜像加速器 4、docker --version 查看docker版本 5、docker info 或 docker system info 显示 Docker 系统的详细信息&#xff0c;包括容器、镜像、网络等 6、docker search 搜索镜像 …

JVM类加载器与双亲委派机制

通过上一篇Java的类加载机制相信大家已经搞明白了整个类加载从触发时机&#xff0c;接着我们就来看下类加载器&#xff0c;因为类加载机制是有加载器实现的。 类加载器的分类 启动类加载器 Bootstrap ClassLoader 是 Java 虚拟机&#xff08;JVM&#xff09;的一部分&#x…

C#调用OpenCvSharp实现图像的直方图均衡化

本文学习基于OpenCvSharp的直方图均衡化处理方式&#xff0c;并使用SkiaSharp绘制相关图形。直方图均衡化是一种图像处理方法&#xff0c;针对偏亮或偏暗的图像&#xff0c;通过调整图像的像素值来增强图像对比度&#xff0c;详细原理及介绍见参考文献1-4。   直方图均衡化第…

【中学教资科目二】02中学课程

02中学课程 第一节 课程概述1.1 课程的分类 第二节 课程组织2.1 课程内容的文本表现形式2.2 课程评价 第三节 基础教育课程改革3.1 基础教育改革的目标3.2 新课改的课程结构 第一节 课程概述 1.1 课程的分类 学校课程有多种类型&#xff0c;其中最利于学生系统掌握人类所取得的…

多维表格/业务库表格大数据量性能瓶颈

先说最终结论&#xff1a;Angular 组件创建性能损耗是当下主要的性能瓶颈 理由&#xff1a; 基于以往编辑器性能优化的经验&#xff0c;编辑器在动态渲染内容时会创建很多壳子组件&#xff08;也就是Angular 组件&#xff09;&#xff0c;排查的时候就发现如果略这些壳子组件性…

mysql--安装跳过验证修改密码安全加固

安装mysql 配置mysql的yum源 [rootVM-0-14-rockylinux ~]# tee /etc/yum.repos.d/mysql.repo << EOF > [MYSQL] > namemysql > baseurlhttps://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-x86_64 > gpgcheck0 > EOF yum安装mysq…

海南聚广众达电子商务咨询有限公司抖音电商新标杆

在数字经济的浪潮中&#xff0c;抖音电商正成为一股不可忽视的力量。海南聚广众达电子商务咨询有限公司&#xff0c;作为专注于抖音电商服务的领军企业&#xff0c;凭借其专业的团队和创新的思维&#xff0c;不断助力商家在抖音平台上实现商业价值的最大化。 海南聚广众达电子…

【ai】tx2-nx:Yolo V4 直接安装与 测试

Yolo V4环境搭建 git clone https://github.com/AlexeyAB/darknet.gitcuda版本和路径也要改成我们的实际版本和路径,否则会编译失败 编译 sudo make nvidia@tx2-nx:~/twork/02_yolov4/darknet$ vi Makefile nvidia@tx2-nx:~/twork/02_yolov4/darknet$ sudo make [sudo

众爱宠物开源项目介绍

众爱宠物管理系统是一个集会员管理、宠物管理、商品管理、库存管理、数据管理、收银管理、多门店管理等功能于一体的综合管理系统&#xff0c;具有操作方便、简单、安全等优点。 开源项目地址

数学建模系列(3/4):典型建模方法

目录 引言 1. 回归分析 1.1 线性回归 基本概念 Matlab实现 1.2 多元回归 基本概念 Matlab实现 1.3 非线性回归 基本概念 Matlab实现 2. 时间序列分析 2.1 时间序列的基本概念 2.2 移动平均 基本概念 Matlab实现 2.3 指数平滑 基本概念 Matlab实现 2.4 ARIM…

Android修行手册-ImageView的adjustViewBounds和设置透明度

点击跳转>GameFramework文档系列&#xff08;二&#xff09;- 场景相关 点击跳转>GameFramework文档系列&#xff08;三&#xff09;- 日志管理和UI 点击跳转>GameFramework文档系列&#xff08;四&#xff09;- 事件订阅 点击跳转>保姆式Cocos合成大西瓜案例 …

HarmonyOS Next 系列之可移动悬浮按钮实现(六)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…

基于强化学习的目标跟踪论文合集

文章目录 2020UAV Maneuvering Target Tracking in Uncertain Environments Based on Deep Reinforcement Learning and Meta-LearningUAV Target Tracking in Urban Environments Using Deep Reinforcement Learning 2021Research on Vehicle Dispatch Problem Based on Kuhn-…

BGP路由反射器实验

实验内容&#xff1a; 通过本实验验证bgp路由反射器的规则 1. 从client收到的路由更新&#xff0c;反射到non-client和client&#xff0c;同时发送给EBGP邻居 2. 从non-client收到的路由更新&#xff0c;只反射到client&#xff0c;同时发送给EBGP邻居 3. 从EBGP邻居收到的路…

PXE自动平台 搭建 银河麒麟 UEFI x86_64 ARM64

1. PXE自动化 原理 要实现PXE自动安装需要以下组件&#xff1a; DHCP服务&#xff1a;服务器通过网络启动时自动分配IP地址。TFTP服务&#xff1a;提供服务器启动下载启动引导EFI。HTTP服务&#xff1a;操作系统镜像下载。 各组件工作原理如下[1]&#xff1a; 开PXE后&…

最新版ChatGPT对话系统源码 Chat Nio系统源码

最新版ChatGPT对话系统源码 Chat Nio系统源码 支持 Vision 模型, 同时支持 直接上传图片 和 输入图片直链或 Base64 图片 功能 (如 GPT-4 Vision Preview, Gemini Pro Vision 等模型) 支持 DALL-E 模型绘图 支持 Midjourney / Niji 模型的 Imagine / Upscale / Variant / Re…

Redis-数据类型-Geospatial(地理空间索引)

文章目录 1、查看redis是否启动2、通过客户端连接redis3、切换到db5数据库4、将地理位置信息&#xff08;经度和纬度&#xff09;添加到 Redis 的键&#xff08;key&#xff09;中4.1、添加大江商厦4.2、添加西部硅谷 5、升序返回有序集key&#xff0c;让分数一起和值返回的结果…

Doris连接超时问题排查记录

文章目录 一、现象描述二、问题排查1、分析驱动包2、分析Mysql客户端&#xff08;问题解决&#xff09; 一、现象描述 先上官网部署地址&#xff0c;按照官网上一步步进行部署 https://doris.apache.org/zh-CN/docs/get-starting/quick-start 基本到最后都挺顺利的&#xff0c…

2022年大作业参考报告-使用C++语言开发小学生成绩管理系统、中学生成绩管理系统、大学生成绩管理系统【240621更新】

背景&#xff1a; 目录 第一章 需求分析 2 1.1 问题描述 2 6.1 功能需求 2 6.2 开发环境 2 6.3 开发过程 2 第二章 概要设计 3 2.1 总体设计 3 2.2 类的定义 3 2.3 接口设计 5 2.4 运行界面设计 6 第三章 详细设计 …