【数据结构】平衡二叉树(AVL树)

目录

前言

一、AVL树概念

二、AVL树节点定义

 三、AVL树插入

1. 按照二叉搜索树的方式插入新节点

2. 维护节点的平衡因子与调整树的结构

 a. 新节点插入较高左子树的左侧---左左:右单旋

b. 新节点插入较高右子树的右侧---右右:左单旋

c. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋 

d. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

四、AVL树删除

附录:AVL树实现参考代码 


前言

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查 找元素相当于在顺序表中搜索元素,效率低下。

因此,两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年发明了一种方法,用以解决上述问题。


一、AVL树概念

AVL 树是一种平衡二叉树,得名于其发明者的名字( Adelson-Velskii 以及 Landis)。(可见名字长的好处,命名都能多占一个字母出来)。平衡二叉树递归定义如下:

  • 左右子树的高度差小于等于 1。
  • 其每一个子树均为平衡二叉树。

 为了使AVL树保持平衡,在节点中增加了一个平衡因子作为节点属性。当树发生变化时,就通过维护平衡因子与改变树的结构来使树保持平衡。

二、AVL树节点定义

template<class K, class V>
struct AVLTreeNode
{
	AVLTreeNode<K, V>* _left;
	AVLTreeNode<K, V>* _right;
	AVLTreeNode<K, V>* _parent;
	std::pair<K, V> _kv;
	int _bf; //balance factor

	AVLTreeNode(const std::pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _bf(0)
	{}
};

 三、AVL树插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么 AVL树的插入过程可以分为两步:

1. 按照二叉搜索树的方式插入新节点

参考二叉搜索树。

【数据结构】二叉搜索树-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/lyhv_v/article/details/139243506

2. 维护节点的平衡因子与调整树的结构

 cur插入后,pParent的平衡因子一定需要调整,在插入之前,pParent 的平衡因子分为三种情况:-1,0, 1, 分以下两种情况:

  1. 如果pCur插入到pParent的左侧,只需给pParent的平衡因子-1即可
  2. 如果pCur插入到pParent的右侧,只需给pParent的平衡因子+1即可

此时:pParent的平衡因子可能有三种情况:0,正负1, 正负2

  1. 如果pParent的平衡因子为0,说明插入之前pParent的平衡因子为正负1,插入后被调整成0,此时满足 AVL树的性质,插入成功
  2. 如果pParent的平衡因子为正负1,说明插入前pParent的平衡因子一定为0,插入后被更新成正负1,此 时以pParent为根的树的高度增加,需要继续向上更新
  3. 如果pParent的平衡因子为正负2,则pParent的平衡因子违反平衡树的性质,需要对其进行旋转处理

 a. 新节点插入较高左子树的左侧---左左:右单旋

Node* RotateR(Node* parent)
{
	Node* sub = parent->_left;
	Node* subR = sub->_right;

	if (parent == _root)
	{
		_root = sub;
		sub->_parent = nullptr;
	}
	else
	{
		Node* up = parent->_parent;
		if (up->_kv.first > sub->_kv.first)
			up->_left = sub;
		else
			up->_right = sub;

		sub->_parent = up;
	}

	parent->_left = subR;
	if (subR != nullptr)
		subR->_parent = parent;
	sub->_right = parent;
	parent->_parent = sub;

	parent->_bf = 0;
	sub->_bf = 0;
	return sub;
}

b. 新节点插入较高右子树的右侧---右右:左单旋

Node* RotateL(Node* parent)
{
	Node* sub = parent->_right;
	Node* subL = sub->_left;

	if (parent == _root)
	{
		_root = sub;
		sub->_parent = nullptr;				
	}
	else
	{
		Node* up = parent->_parent;
		if (up->_kv.first > sub->_kv.first)
			up->_left = sub;
		else
			up->_right = sub;

		sub->_parent = up;
	}

	parent->_right = subL;
	if (subL != nullptr)
		subL->_parent = parent;
	sub->_left = parent;
	parent->_parent = sub;

	parent->_bf = 0;
	sub->_bf = 0;
	return sub;
}

c. 新节点插入较高左子树的右侧---左右:先左单旋再右单旋 

Node* RotateLR(Node* parent)
{
	Node* child = parent->_left;
	Node* sub = child->_right;
	Node* subL = sub->_left;
	Node* subR = sub->_right;

	if (parent == _root)
    {
		_root = sub;
		sub->_parent = nullptr;
	}
	else
	{
		Node* up = parent->_parent;
		if (up->_kv.first > sub->_kv.first)
			up->_left = sub;
		else
			up->_right = sub;

		sub->_parent = up;
	}

	sub->_right = parent;
	parent->_parent = sub;
	sub->_left = child;
	child->_parent = sub;
	parent->_left = subR;
	if (subR != nullptr)
		subR->_parent = parent;
	child->_right = subL;
	if (subL != nullptr)
		subL->_parent = child;

	if (sub->_bf == 1)
	{
		parent->_bf = 0;
		child->_bf = -1;
	}
	else if (sub->_bf == -1)
	{
		parent->_bf = 1;
		child->_bf = 0;
	}
	else
	{
		parent->_bf = 0;
		child->_bf = 0;
	}
	sub->_bf = 0;
	return sub;
}

d. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋

Node* RotateRL(Node* parent)
{
	Node* child = parent->_right;
	Node* sub = child->_left;
	Node* subL = sub->_left;
	Node* subR = sub->_right;

	if (parent == _root)
	{
    	_root = sub;
		sub->_parent = nullptr;
	}
	else
	{
		Node* up = parent->_parent;
		if (up->_kv.first > sub->_kv.first)
			up->_left = sub;
		else
			up->_right = sub;

		sub->_parent = up;
	}

	sub->_left = parent;
	parent->_parent = sub;
	sub->_right = child;
	child->_parent = sub;
	parent->_right = subL;
	if (subL != nullptr)
		subL->_parent = parent;
	child->_left = subR;
	if (subR != nullptr)
		subR->_parent = child;

	if (sub->_bf == 1)
	{
		parent->_bf = -1;
		child->_bf = 0;
	}
	else if (sub->_bf == -1)
	{
		parent->_bf = 0;
		child->_bf = 1;
	}
	else
	{
		parent->_bf = 0;
		child->_bf = 0;
	}
	sub->_bf = 0;
	return sub;
}

四、AVL树删除

因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不 错与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。

具体实现可参考《算法导论》或《数据结构-用面向对象方法与C++描述》殷人昆版。

附录:AVL树实现参考代码 

AVLTree · 梁羽赫/cpp_advanced - 码云 - 开源中国 (gitee.com)icon-default.png?t=N7T8https://gitee.com/yuhe-liang/cpp_advanced/tree/master/AVLTree

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

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

相关文章

前端面试项目细节重难点(已工作|做分享)想(八)

面试官&#xff1a;请你讲讲你在该项目中遇到的印象深刻的问题是什么&#xff1f; 答&#xff1a;我的回答&#xff1a;该项目的实现过程中我确实遇到了问题&#xff1a;【我会给大家整理回答思路和角度&#xff0c;那那么遇到这样的问题也可借鉴这种思路进行阐述】 第一层面…

RocketMQ教程(五):RocketMQ的工作原理2

工作原理 RocketMQ 是一个高性能、高吞吐量的分布式消息和流计算平台,它基于发布-订阅模式工作。其核心设计理念是确保消息传递的高效性、稳定性和可扩展性。RocketMQ 的工作原理主要可以分为以下几个部分: 1. 消息流程 消息发布: Producer 首先向 NameServer 查询目标 Top…

二重,三重积分和曲面,曲线积分的关系和区别

这是我在学习完曲面曲线积分概念后容易和二重三重积分混淆而大概总结和区分了一下&#xff0c;如果有错误请大佬指出&#xff0c;多谢&#xff01;&#xff01;&#xff01;

shell(一)

shell 既是脚本语言又是应用程序 查看自己linux系统的默认解析&#xff1a;echo $SHELL 创建第一个shell 文件 touch 01.sh编辑 vi 01.sh01.sh 文件内容 #!/bin/bash echo felicia保存 按Esc 然后输入:wq 定义以开头&#xff1a;#!/bin/bash #!用来声明脚本由什么shell解释…

无线麦克风什么牌子的音质效果好?一文揭秘领夹麦克风哪个品牌好

​近年来&#xff0c;无线领夹麦克风在各个领域都大放异彩&#xff0c;无论是直播、采访还是上课&#xff0c;都能看到它的身影。这款小小的无线麦克风&#xff0c;蕴含着巨大的能量&#xff0c;为媒体人的创作提供了强大的支持。对于想要更新设备的媒体人来说&#xff0c;现在…

打造国产软硬件一体化解决方案 YashanDB与宏杉科技完成多项兼容互认证

近日&#xff0c;深圳计算科学研究院崖山数据库系统YashanDB与宏杉科技系列存储、系列服务器与数据库一体机等多款产品顺利完成兼容性互认证。经严格测试&#xff0c;双方产品完全兼容&#xff0c;稳定运行&#xff0c;共同提供高效、稳定、安全的国产软硬件一体化解决方案&…

tmux工具使用鼠标滚动窗口及分屏命令

tmux工具使用鼠标滚动窗口及分屏命令 1. tmux source配置文件 长期生效2. 临时生效3. 实现分屏 1. tmux source配置文件 长期生效 vim ~/.tmux.conf echo "set -g mouse on" > ~/.tmux.conf tmux source-file ~/.tmux.conf2. 临时生效 1. 进入到tmux命令窗口 2.…

流水线建构apk、abb实战(一)

在构建机上需要下载的工具 流水线中的构建机无法使用Android Studio中自带的sdk工具下载&#xff0c;所以得下载commandlinetools命令行工具&#xff0c;下载后使用随附的 sdkmanager 下载其他 SDK 软件&#xff0c;解压后按照/cmdline-tools/latest/bin/sdkmanager目录结构整…

【Java毕业设计】基于Java的教师考勤管理系统的设计与实现

文章目录 摘 要ABSTRACT目 录1 概述1.1 研究背景及意义1.2 国内外研究现状1.3 拟研究内容1.4 系统开发技术1.4.1 vue技术1.4.2 B/S结构1.4.3 Spring Boot框架1.4.4 MySQL数据库1.4.5 MVC模式 2 系统需求分析2.1 可行性分析2.2 功能需求分析 3 系统设计3.1 功能结构设计3.2 系统…

红酒保存中的软木塞与瓶身保护

云仓酒庄雷盛红酒&#xff0c;以其卓着的品质和精美的包装赢得了众多消费者的喜爱。在红酒的保存过程中&#xff0c;软木塞与瓶身保护是至关重要的环节。本文将深入探讨这两方面的问题&#xff0c;以帮助消费者更好地理解和欣赏云仓酒庄雷盛红酒。 首先&#xff0c;我们来谈谈软…

神经网络 torch.nn---损失函数与反向传播

torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) torch.nn — PyTorch 2.3 documentation Loss Function的作用 每次训练神经网络的时候都会有一个目标&#xff0c;也会有一个输出。目标和输出之间的误差&#xff0c;就是用Loss Function来衡量的。所以&#xff0c;…

美国签证办理需要带哪些材料?

在申请美国签证时&#xff0c;准备充分的材料至关重要。以下知识人网整理的关于您可能需要携带的一些常见材料&#xff1a; 1.护照&#xff1a;您的护照必须是有效的&#xff0c;并且在签证申请过程中至少有六个月的有效期。 2.签证申请表&#xff1a;您需要填写并提交签证申请…

29 - 买下所有产品的客户(高频 SQL 50 题基础版)

29 - 买下所有产品的客户 selectc.customer_id fromCustomer c group byc.customer_id havingcount(c.product_key)(select count(distinct product_key) from Product);

Windows下安装和配置Redis

目录 1、下载redis压缩包 2、解压redis文件 3、启动redis临时服务 4、打开Redis客户端进行连接 5、使用一些基础操作来测试 5.1、输入ping命令来检测redis服务器与redis客户端的连通性 5.2、使用set和get命令测试redis数据库进行数据存储和获取 5.3、在命令中通过shut…

Easy 同学:AI 时代将加速计算机专业和程序员职业的分化

一、原贴 2024 年 6 月 5 日 拥有 60多万粉丝的方糖气球&#xff08;ftqq.com&#xff09;博主 、独立开发者&#xff1a;Easy 发表了一篇 AI 对计算机专业和程序员行业影响的新浪博客&#xff0c;看后很有启发&#xff0c;故而将原文摘录于此&#xff1a; 单独开个贴说一下吧…

项目实战系列——WebSocket——websock简介

最近项目中需要用到mes和本地客户端进行实时通讯&#xff0c;本来想用webapi进行交互的&#xff0c;但是考虑到高效和实时性&#xff0c;就采用这一项技术。 以往采用的方式——长轮询 客户端主动向服务器发送一个请求&#xff0c;如果服务器没有更新的数据&#xff0c;客户端…

我的python管理

目前环境 Anaconda&#xff1a;python3.9 python2.7 IDA&#xff1a;python3.8 pycharm&#xff1a;&#xff1f;&#xff1f; 以后应该会补吧… 因为某些文件似乎用的python2决定整个python2 安装python2.7 打开anaconda命令行输入 conda create --name python27 python2…

六、Docker Swarm、Docker Stack和Portainer的使用

六、Docker swarm和Docker stack的使用 系列文章目录1.Docker swarm1.简介2.docker swarm常用命令3.docker node常用命令4.docker service常用命令5.实战案例6.参考文章 2.Docker stack1.简介3.Docker stack常用命令4.实战案例5.常见问题及调错方式1.查看报错信息并尝试解决&am…

【简报】VITA 74 (VNX)总结

参考源 VITA 74 &#xff08;VNX&#xff09;A VITA 74 &#xff08;VNX&#xff09;B VITA 74 &#xff08;VNX&#xff09;C VITA 74 &#xff08;VNX&#xff09;D VNX&#xff0c;也称为 VITA 74&#xff0c;在 VITA 标准组织管理的规范中定义。VNX目前已进入“试用”状…

1104 天长地久(测试点1,2,3)

solution 测试点3超时&#xff1a;直接暴力搜超时。m和m1的最大公约数一定是1&#xff0c;则A的个位一定是9才有可能gcd(m, m1)大于1&#xff0c;步长变为10。测试点1&#xff0c;3&#xff1a;m和n的最大公约数是大于2的素数测试点2&#xff1a;按照n从小到大排序&#xff0c…