AVL搜索树

一、介绍

高度平衡的搜索二叉树,保证每个节点的左右子树高度差不超过1,降低搜索树的高度以提高搜索效率。

通过平衡因子和旋转来保证左右子树高度差不超过1

二、插入节点

1、插入规则

(1)搜按索树规则插入节点

(2)更新父节点平衡因子

插入左边就 --,插入右边就 ++

(3)保证父节点平衡因子不超过1

平衡因子是0:表示插入节点之后以父节点为子树的树高度没变,所以插入合法直接跳出。

平衡因子是正负1:以父节点为子树的树高度增大或者减小了1,虽然当前的父节点依旧合法,但是由于高度变了还要向上更新平衡因子。

平衡因子是正负2:要旋转使以父节点为子树的树平衡因子合法。合法后直接挑出。

2、旋转逻辑实现

(1)左高右低 右单旋

旋转前:

旋转后:

大逻辑:把 subLR 给 parent,把 parent 给 subL

右单旋代码实现逻辑和注意点:

a、标记三个节点:subL,subLR,ppNode(保存 parent 的父亲,为了最后更新 subL 的父节点)

b、先 subLR 作 parent 的左子树,注意更新subLR 父节点时 subLR == nullptr 情况

c、再 parent 作 subL 的右子树,注意更新 parent 的父节点

d、利用 ppNode 更新subL 的位置和父节点,注意一开始父节点是根的情况

e、更新 subL 和 parent 的平衡因子为0

右单旋代码:

void RotateR(Node* parent)
{
	Node* subL = parent->_left;
	Node* subLR = subL->_right;
	Node* ppNode = parent->_parent;

	parent->_left = subLR;
	if(subLR)
		subLR->_parent = parent;

	subL->_right = parent;
	parent->_parent = subL;

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

(2)右高左低 左单旋

旋转前:

旋转后:

分析过程和右单旋类似,代码如下:

void RotateL(Node* parent)
{
	Node* subR = parent->_right;
	Node* subRL = subR->_left;
	Node* ppNode = parent->_parent;

	parent->_right = subRL;
	if (subRL)
		subRL->_parent = parent;

	subR->_left = parent;
	parent->_parent = subR;

	if (parent == _root)
	{
		_root = subR;
		_root->_parent = nullptr;
	}
	else
	{
		if (ppNode->_left == parent)
		{
			ppNode->_left = subR;
			subR->_parent = ppNode;
		}
		else
		{
			ppNode->_right = subR;
			subR->_parent = ppNode;
		}
	}
	parent->_bf = subR->_bf = 0;
}

(3)左高右高 左右双旋

旋转图:

左右双旋的本质就是把 subLR 的左子树给 subL,右子树给 parent

通过本质就可以知道三种不同情况的平衡因子:

              插入前 subLR 平衡因子             插入后平衡因子
subLR subLparent 
-1(新节点插在 subLR 的左子树)001
1(新节点插在 subLR 的右子树)0-10
0(新节点就是 subLR)000

左右双旋代码:

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

	RotateL(subL);
	RotateR(parent);

	if (bf == -1)
	{
		subL->_bf = 0;
		parent->_bf = 1;
		subLR->_bf = 0;
	}
	else if (bf == 1)
	{
		subL->_bf = -1;
		parent->_bf = 0;
		subLR->_bf = 0;
	}
	else if (bf == 0)
	{
		subL->_bf = 0;
		parent->_bf = 0;
		subLR->_bf = 0;
	}
	else
		assert(false);
}

(4)右高左高 右左双旋

旋转图:

右左双旋的本质就是把 subRL 的左子树给 parent,右子树给 subR

通过本质就可以知道三种不同情况的平衡因子:

              插入前 subRL 平衡因子             插入后平衡因子
subRL subRparent 
-1(新节点插在 subRL 的左子树)010
1(新节点插在 subRL 的右子树)00-1
0(新节点就是 subRL)000

右左双旋代码:

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

	RotateR(subR);
	RotateL(parent);

	if (bf == 1)
	{
		subR->_bf = 0;
		parent->_bf = -1;
		subRL->_bf = 0;
	}
	else if (bf == -1)
	{
		subR->_bf = 1;
		parent->_bf = 0;
		subRL->_bf = 0;
	}
	else if (bf == 0)
	{
		subR->_bf = 0;
		parent->_bf = 0;
		subRL->_bf = 0;
	}
	else
		assert(false);
}

3、插入代码展示

bool insert(const pair<K, V> kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}

	Node* cur = _root;
	Node* parent = cur;
	// 1.像搜索二叉树一样插入节点cur
	while (cur)
	{
		if (cur->_kv.first > kv.first)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_kv.first < kv.first)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
			return false;
	}

	cur = new Node(kv);
	if (parent->_kv.first < kv.first)
		parent->_right = cur;
	else
		parent->_left = cur;
	cur->_parent = parent;

	// 2.更新平衡因子
	while (parent)
	{
		if (cur == parent->_left)
			parent->_bf--;
		else
			parent->_bf++;

		if (parent->_bf == 0)
			break;
		else if (parent->_bf == 1 || parent->_bf == -1)
		{
			cur = parent;
			parent = parent->_parent;
		}
		else if (parent->_bf == 2 || parent->_bf == -2)
		{
			// 左高右低右单旋
			if (parent->_bf == -2 && cur->_bf == -1)
				RotateR(parent);
			// 右高左低左单旋
			else if (parent->_bf == 2 && cur->_bf == 1)
				RotateL(parent);
			// 左高右高左右双旋
			else if (parent->_bf == -2 && cur->_bf == 1)
				RotateLR(parent);
			// 右高左高右左双旋
			else
				RotateRL(parent); 
			break;
		}
		else
			assert(false);
	}
	return true;
}

三、删除节点

这里只了解删除逻辑,具体如何旋转不考虑。

删除规则

按搜索树删除

删除并更新平衡因子

删除左边就 ++,删除右边就 --

保证父节点平衡因子不超过1

平衡因子是0:表示删除结点之前是正负1,删除后高度改变,所以要向上继续更新。

平衡因子是正负1:表示删除结点之前是0,删除后高度不变,所以跳出。

平衡因子是正负2:要旋转使以父节点为子树的树平衡因子合法。合法后直接跳出。

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

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

相关文章

unity导入图片素材注意点和AI寻路模块导入

当我们导入了图片资源&#xff0c;我们需要设置为Sprite类型 UI资源的位置通常是Rect Transform 要进行转化&#xff1a; (imgHP.transform as RectTransform).sizeDelta new Vector2((float)hp / maxHP * hpW,74); RectTransform 是Unity中用于UI元素的特殊变换组件&#…

中国网络安全产业分析报告

网络安全是总体国家安全观的重要组成部分&#xff0c;切实维护网络空间安全&#xff0c;筑牢国家网络安全屏障&#xff0c;已成为关系我国发展全局的重大战略任务。近年来&#xff0c;我国网信相关部门深入推进网络安全治理&#xff0c;网络安全政策法规体系更加健全&#xff0…

kimi,天工,gpt,deepseek效果对比

偶然间碰到的这个问题&#xff0c;这个问题感觉有点意思&#xff0c;他不是定义性的问题&#xff0c;而是不同概念之间的区别对比&#xff0c;我觉得这个效果立竿见影&#xff0c;一看就能看出来回答问题水平的层次。 单纯这个问题的答案&#xff0c;deepseek远超gpt&#xff…

Github 2025-01-30 Go开源项目日报 Top10

根据Github Trendings的统计,今日(2025-01-30统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目10Ollama: 本地大型语言模型设置与运行 创建周期:248 天开发语言:Go协议类型:MIT LicenseStar数量:42421 个Fork数量:2724 次关注人…

MySQL查询优化(三):深度解读 MySQL客户端和服务端协议

如果需要从 MySQL 服务端获得很高的性能&#xff0c;最佳的方式就是花时间研究 MySQL 优化和执行查询的机制。一旦理解了这些&#xff0c;大部分的查询优化是有据可循的&#xff0c;从而使得整个查询优化的过程更有逻辑性。下图展示了 MySQL 执行查询的过程&#xff1a; 客户端…

【4Day创客实践入门教程】Day3 实战演练——桌面迷你番茄钟

Day3 实战演练——桌面迷你番茄钟 目录 Day3 实战演练——桌面迷你番茄钟1. 选择、准备元件、收集资料2. 硬件搭建3.编写代码 Day0 创想启程——课程与项目预览Day1 工具箱构建——开发环境的构建Day2 探秘微控制器——单片机与MicroPython初步Day3 实战演练——桌面迷你番茄钟…

leetcode 2300. 咒语和药水的成功对数

题目如下 数据范围 示例 注意到n和m的长度最长达到10的5次方所以时间复杂度为n方的必然超时。 因为题目要求我们返回每个位置的spell对应的有效对数所以我们只需要找到第一个有效的药水就行&#xff0c;这里可以先对potions排序随后使用二分查找把时间复杂度压到nlogn就不会…

Android Studio 正式版 10 周年回顾,承载 Androider 的峥嵘十年

Android Studio 1.0 宣发于 2014 年 12 月&#xff0c;而现在时间来到 2025 &#xff0c;不知不觉间 Android Studio 已经陪伴 Androider 走过十年历程。 Android Studio 10 周年&#xff0c;也代表着了我的职业生涯也超十年&#xff0c;现在回想起来依然觉得「唏嘘」&#xff…

互斥锁/信号量实现5个线程同步

互斥锁 实现同步 互斥锁保证在同一时刻&#xff0c;只有一个线程可以访问共享资源&#xff0c;从而实现了线程同步。 思路 1 创建互斥锁(1个) pthread_mutex_t mutex; 2 初始化互斥锁 所有线程开始执行前&#xff0c;pthread_mutex_init(&mutex, …

WordPress Web Directory Free插件本地包含漏洞复现(附脚本)(CVE-2024-3673)

免责申明&#xff1a; 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权&#xff0c;请及时与我们联系&#xff0c;我们将…

系统学习算法: 专题七 递归

递归算法简而言之就是当一个大问题拆分为多个子问题时&#xff0c;如果每个子问题的操作步骤都一样&#xff0c;就可以用递归&#xff0c;其中递归在递的时候要有结束条件&#xff0c;不能一直递下去&#xff0c;结束条件后就归 这里不建议学习递归的时候抠细节&#xff0c;还…

单片机基础模块学习——PCF8591芯片

一、A/D、D/A模块 A——Analog 模拟信号:连续变化的信号(很多传感器原始输出的信号都为此类信号)D——Digital 数字信号:只有高电平和低电平两种变化(单片机芯片、微控制芯片所能处理的都是数字信号) 下面是模拟信号和连续信号的区别 为什么需要进行模拟信号和数字信号之…

从未标记图像中生成有标记图像特征的半监督分割方法

今天看到一篇文章很有意思&#xff0c;给大家分享一下。现在传统半监督分割网络训练时往往有标注数据与未标注数据分开训练&#xff0c;导致模型不好。这篇文章作者提出了一个很有意思的想法。它通过通道注意力从未标记的特征中重新加载标记的特征。这篇文章是AllSpark。 大家感…

17.1 图像操作

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.1.1 Image类 Image类为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。 Image的属性大多数是只读的&#xff1a; FrameDim…

实验七 JSP内置对象II

实验七 JSP内置对象II 目的&#xff1a; 1、掌握JSP内置对象的使用。 2、理解JSP的作用域 3、掌握session&#xff0c;application对象的使用 实验要求&#xff1a; 1、完成实验题目 2、要求提交实验报告&#xff0c;将代码和实验结果页面截图放入报告中 实验过程&#xff1a…

每日一博 - 三高系统架构设计:高性能、高并发、高可用性解析

文章目录 引言一、高性能篇1.1 高性能的核心意义 1.2 影响系统性能的因素1.3 高性能优化方法论1.3.1 读优化&#xff1a;缓存与数据库的结合1.3.2 写优化&#xff1a;异步化处理 1.4 高性能优化实践1.4.1 本地缓存 vs 分布式缓存1.4.2 数据库优化 二、高并发篇2.1 高并发的核心…

FFmpeg(7.1版本)的基本组成

1. 前言 FFmpeg 是一个非常流行的开源项目&#xff0c;它提供了处理音频、视频以及其他多媒体内容的强大工具。FFmpeg 包含了大量的库&#xff0c;可以用来解码、编码、转码、处理和播放几乎所有类型的多媒体文件。它广泛用于视频和音频的录制、转换、流媒体传输等领域。 2. F…

灵芝黄金基因组注释-文献精读109

The golden genome annotation of Ganoderma lingzhi reveals a more complex scenario of eukaryotic gene structure and transcription activity 灵芝&#xff08;Ganoderma lingzhi&#xff09;的黄金基因组注释揭示了更复杂的真核基因结构和转录活性情况 摘要 背景 普遍…

51单片机入门_01_单片机(MCU)概述(使用STC89C52芯片;使用到的硬件及课程安排)

文章目录 1. 什么是单片机1.1 微型计算机的组成1.2 微型计算机的应用形态1.3 单板微型计算机1.4 单片机(MCU)1.4.1 单片机内部结构1.4.2 单片机应用系统的组成 1.5 80C51单片机系列1.5.1 STC公司的51单片机1.5.1 STC公司单片机的命名规则 2. 单片机的特点及应用领域2.1 单片机的…

记忆化搜索(5题)

是什么&#xff1f; 是一个带备忘录的递归 如何实现记忆化搜索 1.添加一个备忘录&#xff08;建立一个可变参数和返回值的映射关系&#xff09; 2.递归每次返回的时候把结果放到备忘录里 3.在每次进入递归的时候往备忘录里面看看。 目录 1.斐波那契数列 2.不同路径 3.最…