AVL树

news2024/11/25 20:50:39

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:那个传说中的man的主页
🏠个人专栏:题目解析
🌎推荐文章:题目大解析(3)

在这里插入图片描述


目录

  • 👉🏻AVL树概念
  • 👉🏻AVL树模拟实现
    • insert插入
      • 左旋
      • 右旋
      • 双旋:先右单旋再左单旋
    • 判断是否为平衡树
    • 未完待续

👉🏻AVL树概念

AVL树是一种自平衡二叉搜索树,它在插入和删除操作后会通过旋转操作来保持树的平衡。它得名于发明者Adelson-VelskyLandis

AVL树的特点是,对于任意节点,其左子树的高度与右子树的高度之差(即平衡因子)不超过1。当插入或删除操作导致某个节点的平衡因子超过1时,就需要进行旋转操作来调整树的结构,使之重新满足平衡条件。

A V L 树的性质如下 AVL树的性质如下 AVL树的性质如下

  • 它的左右子树都是AVL树
  • 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

平衡因子
1:左边矮,右边高
0:一样高
-1:左边高,右边矮

在这里插入图片描述


AVL树的旋转操作分为两种:左旋和右旋。左旋用于处理左子树过深的情况,而右旋用于处理右子树过深的情况。通过这两种旋转操作的组合,可以实现AVL树的自平衡。

插入元素时,先按照二叉搜索树的规则找到插入位置,并将新节点插入为叶子节点。然后,从插入位置向上回溯,更新每个祖先节点的高度,并检查是否违反了平衡条件。如果发现某个祖先节点的平衡因子超过1,则进行相应的旋转操作来恢复平衡。

删除元素时,先按照二叉搜索树的规则找到待删除的节点,并进行删除操作。然后,从删除位置向上回溯,更新每个祖先节点的高度,并检查是否违反了平衡条件。如果发现某个祖先节点的平衡因子超过1,则进行相应的旋转操作来恢复平衡。

AVL树的自平衡性保证了查找、插入和删除等操作的时间复杂度都能保持在O(log n)级别,使其成为一种高效的数据结构。然而,AVL树相对于其他平衡二叉搜索树(如红黑树)来说,需要更多的旋转操作,因此在频繁插入和删除操作的场景下,可能会导致性能的略微下降。

👉🏻AVL树模拟实现

insert插入

左旋

左旋前提条件

  • parent ->bf = 2
  • cur->bf = 1
    在这里插入图片描述
    1.让parent->right = subRL;subR->left = parent;
    2.此时还要更新根节点、parent的parent、subRL的parent(这个需要考虑subRL是否为空)
    3.更新subR的parent,此时要考虑parent是否为根节点或非根节点两种情况。前者直接root = subR,subR->parent = nullptr,若为后者,则要另外讨论。
    代码如下: 👇🏻
void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		//1.让parent->right = subRL;subR->left = parent;
		parent->_right = subRL;
		subR->_left = parent;
		//2.此时还要更新根节点、parent的parent、subRL的parent(**这个需要考虑subRL是否为空**)
		Node* parentParent = parent->_parent;
		parent->_parent = subR;
		if (subRL)
			subRL->_parent = parent;
		//更新subR的parent,此时要考虑parent是否为根节点或非根节点两种情况
		
		if (_root == parent)
		{
			_root = subR;
			subR->_parent = nullptr;

		}
		else
		{
			if (parentParent->_left == parent)//如果parent是parentParent的左节点,则作为新的"parent"的subR就要是parentParent的左节点,其parent为parentParent
			{
				parentParent->_left = subR;
				subR->_parent = parentParent;
			}
			else
			{
				parentParent->_right = subR;
				subR->_parent = parentParent;
			}
		}
		parent->_bf = subR->_bf = 0;
	}

右旋

右旋前提条件

  • parent ->bf = -2
  • cur->bf = -1
    在这里插入图片描述
    同理左旋
    代码如下: 👇🏻
void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		//1.让parent->left = subLR;subL->right = parent;
		parent->_left = subLR;
		subL->_right = parent;
		//2.此时还要更新根节点、parent的parent、subLR的parent(**这个需要考虑subRL是否为空**)
		Node* parentParent = parent->_parent;
		parent->_parent = subL;

		if (subLR)
			subLR->_parent = parent;
		//3.更新subL的parent,此时要考虑parent是否为根节点或非根节点两种情况
		if (_root == parent)
		{
			_root = subL;
			subL->_parent = nullptr;

		}
		else
		{
			if (parentParent->_left == parent)//如果parent是parentParent的左节点,则作为新的"parent"的subR就要是parentParent的左节点,其parent为parentParent
			{
				parentParent->_left = subL;
				subL->_parent = parentParent;
			}
			else
			{
				parentParent->_right = subL;
				subL->_parent = parentParent;
			}
		}
		parent->_bf = subL->_bf = 0;
	}

双旋:先右单旋再左单旋

为什么要双旋转,是因为有单单左旋或右旋解决不了的情况:👇🏻👇🏻
在这里插入图片描述
如上情况就左单旋无法解决问题
我们现在将上述的情况中的b子树再细分讨论
在这里插入图片描述

  • a,d:高度为h(h>=0)
  • b.c:高度为h-1,b,c可能为空树(h>=1)

而以上又可以分为三种插入情况
在这里插入图片描述

在这里插入图片描述

但无论是哪种情况,都遵循一样的旋转步骤:
1.90为旋转点进行右旋
2.30为旋转点进行左旋
所以大致流程图可以表示为:👇🏻
在这里插入图片描述
先右单旋再左单旋前提条件

  • parent->_bf == 2
  • cur->_bf == -1

所以大致步骤如下:
1.先对parent进行右旋
2.再对parent->right左旋
3.对parentsubRsubRL的bf进行更新
代码如下: 👇🏻

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

		int bf = subRL->_bf;
		//先对parent进行右旋,再对parent->right左旋
		RotateR(parent);
		RotateL(parent->_left);

		//对**parent**、**subR**、**subRL**的bf进行更新
		//这里要考虑三种插入情况
		if (bf == 0)
		{
			// subRL自己就是新增
			subR->_bf = subRL->_bf = parent->_bf = 0;
		}
		else if (bf == -1)
		{
			//subRL左子树新增
			subR->_bf = 1;
			subRL->_bf = parent->_bf = 0;
		}
		else if (bf == 1)
		{
			//subRL右子树新增
			parent->_bf = -1;
			subRL->_bf = subR->_bf = 0;
		}
		else
		{
			assert(false);
		}

	}

判断是否为平衡树

bool IsBalance()
	{
		return _IsBalance(_root);
	}

	int _Height(Node* root)
	{
		if (root == nullptr)
			return 0;

		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);

		return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
	}

	bool _IsBalance(Node* root)
	{
		if (root == nullptr)
			return true;

		int leftHeight = _Height(root->_left);
		int rightHeight = _Height(root->_right);
		if (rightHeight - leftHeight != root->_bf)
		{
			cout << root->_kv.first << "平衡因子异常" << endl;
			return false;
		}

		return abs(rightHeight - leftHeight) < 2
			&& _IsBalance(root->_left)
			&& _IsBalance(root->_right);
	}

未完待续

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

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

相关文章

专业媒体播放软件Movist Pro中文

Movist Pro是一款专为Mac用户设计的专业媒体播放器。它支持广泛的视频和音频格式&#xff0c;包括MP4、AVI、MKV等&#xff0c;并提供了高级播放控件和定制的视频设置。其直观易用的用户界面&#xff0c;使得播放高清视频更为流畅&#xff0c;且不会卡顿或滞后。同时&#xff0…

海康Visionmaster-全局触发:使用全局触发功能执行流 程的方法

我们这里以 TCP 通讯为例&#xff0c;视觉作为 TCP 服务端&#xff0c;与视觉交互的第三方设备作为 TCP 客户端。当 TCP 客户端连接上视觉服务端后&#xff0c;客户端发送字符串 T1,视觉执行流程 1&#xff1b; 客户端发送字符串 T2&#xff0c;视觉执行流程 2。 这样的需求我…

在 CelebA 数据集上训练的 PyTorch 中的基本变分自动编码器

摩西西珀博士 一、说明 我最近发现自己需要一种方法将图像编码到潜在嵌入中&#xff0c;调整嵌入&#xff0c;然后生成新图像。有一些强大的方法可以创建嵌入或从嵌入生成。如果你想同时做到这两点&#xff0c;一种自然且相当简单的方法是使用变分自动编码器。 这样的深度网络不…

Markdown语法教程

Markdown&#xff1a;一种轻量级语言&#xff0c;有简洁的编写方式&#xff0c;能够提高大家的工作效率。 一、标题 1.1 标题 标题的编写格式以#号开始&#xff0c;分别表示h1 ~ h6&#xff0c;注意&#xff1a;# 后面有空格&#xff01; # 一级标题 ## 二级标题 ### 三级标题…

K8s学习笔记——认识理解篇

1. K8s诞生背景 回顾应用的部署&#xff0c;经历了以下几个阶段&#xff1a; 传统部署&#xff1a;物理服务器上运行应用程序。虚拟机部署&#xff1a;物理服务器上安装虚拟机&#xff0c;在虚拟机上运行应用程序。容器部署&#xff1a;物理服务器上安装容器运行时&#xff0…

MINIO minio 安装 报错 问题

minio MINIO 安装 报错 问题 前言问题1问题产生原因分析解决方案 问题2原因分析解决方案 问题3问题产生原因分析解决方案 问题4问题产生 原因分析解决方案 问题5问题产生 原因分析解决方案 关键词&#xff1a; 1: WARNING: MINIO_ACCESS_KEY and MINIO_SECRET_KEY are deprecat…

全能数据分析软件 Tableau Desktop 2019 mac中文版功能亮点

Tableau Desktop 2019 mac是一款专业的全能数据分析工具&#xff0c;可以让用户将海量数据导入并记性汇总&#xff0c;并且支持多种数据类型&#xff0c;比如像是编程常用的键值对、哈希MAP、JSON类型数据等&#xff0c;因此用户可以将很多常用数据库文件直接导入Tableau Deskt…

2019 ICPC 银川题解(A)

赛时没发挥好6题金尾&#xff08;rank38&#xff09;&#xff0c;剩下很多能写的题&#xff0c;其中四个dp&#xff0c;傻眼ing A Girls Band Party&#xff08;背包&#xff09; 有点迷惑的题&#xff0c;当时看只要 5 5 5 张牌一下子想到暴力枚举&#xff0c;结果发现是不…

【漏洞复现】Redis未授权

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、影响版本1.3、漏洞复现环境搭建写入计划任务获取反弹shell利用SSH写公钥&#xff0c;免密登陆利用Redis写WebShell 3、检测未授权访问漏洞检测工具参考 1.1…

《 Hello 算法 》 - 免费开源的数据结构与算法入门教程电子书,包含大量动画、图解,通俗易懂

这本学习算法的电子书应该是我看过这方面最好的书了&#xff0c;代码例子有多种编程语言&#xff0c;JavaScript 也支持。 《 Hello 算法 》&#xff0c;英文名称是 Hello algo&#xff0c;是一本关于编程中数据解构和算法入门的电子书&#xff0c;作者是毕业于上海交通大学的…

零代码复现-TCGA联合GEO免疫基因结合代谢基因生信套路(三)

前面的分析中&#xff0c;整理好的关键基因集表达谱矩阵&#xff0c;接下来就准备分子亚型的相关分析。 六、一致性聚类构建分子亚型 在6.TCGA和GEO差异基因获取和预后数据的整理\TCGA文件中获取文件 准备一个生存数据和表达谱矩阵&#xff0c;这里需要注意的是&#xff0c;…

基于Jenkins实现接口自动化持续集成,学完涨薪5k

一、JOB项目配置 1、添加描述 可选选项可填可不填 2、限制项目的运行节点 节点中要有运行环境所需的配置 节点配置教程&#xff1a;https://blog.csdn.net/YZL40514131/article/details/131504280 3、源码管理 需要将脚本推送到远程仓库中 4、构建触发器 可以选择定时构建…

【爬虫实战】用python爬取微博任意关键词搜索结果、exe文件

项目功能简介&#xff1a; 1.交互式配置&#xff1b; 2.两种任意关键词来源&#xff08;直接输入、本地关键词文件&#xff09;&#xff1b; 3.自动翻页(无限爬取)&#xff1b; 4.指定最大翻页页码&#xff1b; 5.数据保存到csv文件&#xff1b; 6.程序支持打包成exe文件…

Go类型嵌入介绍和使用类型嵌入模拟实现“继承”

Go类型嵌入介绍和使用类型嵌入模拟实现“继承” 文章目录 Go类型嵌入介绍和使用类型嵌入模拟实现“继承”一、独立的自定义类型二、继承三、类型嵌入3.1 什么是类型嵌入 四、接口类型的类型嵌入4.1 接口类型的类型嵌入介绍4.2 一个小案例 五、结构体类型的类型嵌入5.1 结构体类…

视频视觉效果制作After Effects 2023 MacOS中文

After Effects 2023是一款业界领先的动态图形和视觉特效软件。它提供了强大的工具集&#xff0c;帮助用户创建引人入胜的视觉效果、动态图形和电影级特效。新的版本带来了更快的渲染速度、增强的图像处理和优化的工作流程&#xff0c;使用户能够更高效地工作。无论您是在电影、…

Kotlin 进阶函数式编程技巧

Kotlin 进阶函数式编程技巧 Kotlin 简介 软件开发环境不断变化&#xff0c;要求开发人员不仅适应&#xff0c;更要进化。Kotlin 以其简洁的语法和强大的功能迅速成为许多人进化过程中的信赖伙伴。虽然 Kotlin 的初始吸引力可能是它的简洁语法和与 Java 的互操作性&#xff0c…

idea文件比对

idea文件比对 1.项目内的文件比对2.项目间的文件比对3. 剪切板对比4. 版本历史(不同分支和不同commit)对比 1.项目内的文件比对 在项目中选择好需要比对的文件(类)&#xff0c;然后选择Compare Files Mac下的快捷键是Commandd&#xff0c; 这样的比对像是git冲突解决一样 …

Peter算法小课堂—单调子序列

最长上升子序列 dp解法&#xff1a; f[i]表示以i结尾的最长上升子序列的长度 按照倒数第二个选谁分类&#xff1a; 我们先扫描i号元素前的每个元素&#xff08;正向&#xff09;&#xff0c;找出第一个比i号元素小的元素k号。①仍然选i号元素&#xff0c;f[i]。②选k号&…

selenium自动化测试入门 —— cookie 处理

driver.get_cookies() # 获得cookie 信息 driver.get_cookies(name) # 获得对应name的cookie信息 add_cookie(cookie_dict) # 向cookie 添加会话信息 delete_cookie(name) # 删除特定(部分)的cookie delete_all_cookies() # 删除所有cookie 示例&#xff1a; from sel…

2022年电工杯数学建模B题5G网络环境下应急物资配送问题求解全过程论文及程序

2022年电工杯数学建模 B题 5G网络环境下应急物资配送问题 原题再现&#xff1a; 一些重特大突发事件往往会造成道路阻断、损坏、封闭等意想不到的情况&#xff0c;对人们的日常生活会造成一定的影响。为了保证人们的正常生活&#xff0c;将应急物资及时准确地配送到位尤为重要…