【数据结构】AVL树的插入和自平衡调整

news2024/12/24 0:09:16

AVL树是最早发明的自平衡二叉查找树。在AVL树中,任一节点对应的两颗子树的最大高度差为1,因此他被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是 O ( log ⁡ n ) O(\log{n}) O(logn)增加和删除操作后可能需要通过一次货多次旋转来实现平衡

AVL树结构

  • 可以是空树
  • 任一节点对应的两颗子树的最大高度差为1

下面的两颗树就不是AVL树
在这里插入图片描述
50节点的左子树高度为2右子树的高度为0;60节点左子树高度为3左子树高度为1,不满足条件。
在这里插入图片描述
50节点的左子树高度为2右子树的高度为0;60节点左子树高度为3左子树高度为1,不满足条件。

下面这棵树是AVL树
在这里插入图片描述

节点结构

typedef struct AVL
{
	int data;
	int bf;				//平衡因子
	struct AVL* left;
	struct AVL* right;
	struct AVL* parent;
}AVL;

平衡因子为右子树和左子树的高度差

平衡因子取值含义
0左子树和右子树一样高
1右子树比左子树高1
-1左子树比右子树高1
2不平衡了,需要通过旋转平衡
-2不平衡了,需要通过旋转平衡

AVL树的插入

AVL树插入节点的步骤

  1. 按照二叉搜索树的插入方法找到待插入节点
  2. 找到待插入节点后,将节点插入树中。
  3. 更新平衡因子,判断是否需要继续更新/旋转
  4. 如果需要旋转,判断旋转类型

更新平衡因子的规则

  • 如果插入节点是parent的左孩子,则parent的平衡因子–
  • 如果插入节点是parent的右孩子,则parent的平衡因子++

更新完一个节点的平衡因子后的判断

  • 如果parent平衡因子为1或-1,则要继续往上更新
  • 如果parent的平衡因子为0,则无需继续往上更新平衡因子
  • 如果parent的平衡因子为2或-2,则表明以parent为根的子树已经不平衡,需要进行旋转。
    解释
  • 因为只有parent的平衡因子为0时经过++或者–操作才会变成1/-1,这说明插入后parent的左子树或者右子树变高了,那么以parent为根的子树变高了,从而影
    响了parent的父节点的平衡因子,所以要往上更新。
  • 因为只有parent的平衡因子为-1/1时经过++或者–操作才会变成0,说明插入前parent左右子树高度不一,新节点插入到了较矮的子树上,那么插入后并没有影响以parent为根的树的高度,从而不会影响parent的父节点的平衡因子。

判断旋转类型

向上更新的过程中必然指向下面的逻辑

cur=parent;
parent=parent->_parent;

那么根据cur的平衡因子和parent的平衡因子就可以判断旋转类型

parent->bfcur->bf旋转类型
21左单旋
2-1右左双旋
-21左右双旋
-2-1右单旋

在这里插入图片描述
如图所示插入节点13,向上更新parent的平衡因子,节点12的平衡因子由0—>1
节点15的平衡因子由1—>0,结束平衡因子的更新。

bool Insert(AVL** root, int data)
{
	if (!(*root))
	{
		*root = CreateNode(data);
		return true;
	}

	AVL* cur = *root;
	AVL* parent = NULL;
	//找
	while (cur)
	{
		if (data > cur->data)
		{
			parent = cur;
			cur = cur->right;
		}
		else if (data < cur->data)
		{
			parent = cur;
			cur = cur->left;
		}
		else
			return false;
	}
	cur = CreateNode(data);
	//插(左/右)
	if (data < parent->data)
	{
		parent->left = cur;
		cur->parent = parent;
		/*parent->bf--;*/
		/*现在还不是更新平衡因子的时候*/
	}
	else
	{
		parent->right = cur;
		cur->parent = parent;
		/*parent->bf++;*/
		/*现在还不是更新平衡因子的时候*/
	}
	//更新平衡因子
	while (cur != *root)
	{
		if (cur == parent->left)
		{
			parent->bf--;
		}
		else
		{
			parent->bf++;
		}
		
		//需要继续向上找
		if (parent->bf == 1 || parent->bf == -1)
		{
			cur = parent;
			parent = parent->parent;
			//结束
			if (parent == NULL || parent->bf == 0)
				break;
		}
		
		//需要旋转
		if (parent->bf == 2 || parent->bf == -2)
		{
			if (parent->bf == 2)
			{
				if (cur->bf == 1)
					RotateL(parent);
				else if(cur->bf == -1)
					RotateRL(parent);
			}
			else if(parent->bf == -2)
			{
				if (cur->bf == 1)
					RotateLR(parent);
				else if(cur->bf == -1)
					RotateR(parent);
			}
		}
	}
	return true;
}

旋转处理

左单旋

在这里插入图片描述
步骤

  1. cR的左子树作为parent的右子树
  2. parent成为cR的左子树
  3. cR成为子树的根
  4. cR插入到树中
  5. 更新平衡因子

右单旋

在这里插入图片描述
步骤

  1. cL的右子树成为parent的左子树
  2. parent成为cL的右子树
  3. cL成为子树的根
  4. cL插入到树中
  5. 更新平衡因子

左右单旋

插入节点
在这里插入图片描述
左单旋
在这里插入图片描述
右单旋
在这里插入图片描述

平衡因子更新的三种情况

在这里插入图片描述
2.
在这里插入图片描述
3.
在这里插入图片描述

右左单旋

插入节点
在这里插入图片描述
右单旋
在这里插入图片描述
左单旋
在这里插入图片描述

void RotateRL(AVL* parent)
{
	AVL* cR = parent->left;
	AVL* cRL = cR->right;
	int bf = cRL->bf;
	RotateR(cR);
	RotateL(parent);
	//更新平衡因子
	if (bf == 1)
	{
		parent->bf = -1;
		cR->bf = 0;
		cRL->bf = 0;
	}
	if (bf == 0)
	{
		parent->bf = 0;
		cR->bf = 0;
		cRL->bf = 0;
	}
	if (bf == -1)
	{
		parent->bf = 0;
		cR->bf = 1;
		cRL->bf = 0;
	}
}

验证平衡二叉树

平衡二叉树是一种加了平衡限制的二叉查找树,所以通过中序遍历可以验证是否为一颗二叉查找树。通过后序遍历,从叶子节点开始获取每个节点左右子树的高(以该节点为根的子树高为 左右子树中高度的较大值 + 1)

bool isBalanced(AVL* root, int* phight)
{
	if (root == NULL)
	{
		return true;
	}
	int leftHight = 0;
	if (isBalanced(root->left, &leftHight) == false)
		return false;
	int rightHight = 0;
	if (isBalanced(root->right, &rightHight) == false)
		return false;

	/*if (rightHight - leftHight != root->bf)
		printf("平衡因子设置异常\n");*/
	*phight = MAX(leftHight, rightHight) + 1;

	return abs(rightHight - leftHight) < 2;
}

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

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

相关文章

斯坦福兔子,犰狳,obj模型下载

序 这俩&#xff0c;可能是计算机图形学里比较有名的模型。 但是&#xff0c;官方网站上下载的话&#xff0c;模型是ply格式的&#xff0c;不大习惯&#xff1b;想要obj格式的。 有没有现成的obj格式的&#xff1f; 相关网页 PositionBasedDynamics/data/models at master…

动态规划之子数组系列

子数组系列 1. 环形⼦数组的最⼤和2. 乘积最大子数组3. 等差数列划分4. 最长湍流子数组5. 单词拆分6. 环绕字符串中唯⼀的子字符串 1. 环形⼦数组的最⼤和 1.题目链接&#xff1a;环形⼦数组的最⼤和 2.题目描述&#xff1a;给定一个长度为 n 的环形整数数组 nums &#xff0c…

Pytorch-基于RNN的不同语种人名生成模型

一、RNN背景介绍 循环神经网络&#xff08;Recurrent Neural Networks, RNN&#xff09; 是一种常用的神经网络结构&#xff0c;它源自于1982年由Saratha Sathasivam提出的霍普菲尔德网络。 其特有的循环概念及其最重要的结构——长短时记忆网络——使得它在处理和预测序列数据…

Linux初探 - 概念上的理解和常见指令的使用

目录 Linux背景 Linux发展史 GNU 应用场景 发行版本 从概念上认识Linux 操作系统的概念 用户的概念 路径与目录 Linux下的文件 时间戳的概念 常规权限 特殊权限 Shell的概念 常用指令 ls tree stat clear pwd echo cd touch mkdir rmdir rm cp mv …

请求与响应以及REST风格

目录 请求与响应请求参数参数传递 五种类型参数传递普通参数POJO数据类型嵌套POJO类型参数数组类型参数集合类型参数JSON数据传输参数JSON对象数据JSON对象数组 响应返回文本数据[了解]响应JSON数据 REST风格REST简介RESTful入门案例RESTful快速开发 请求与响应 请求参数 参数…

【SpringMVC】实现增删改查(附源码)

目录 引言 一、前期准备 1.1.搭建Maven环境 1.2.导入pom.xml依赖 1.3.导入配置文件 ①jdbc.properties ②generatorConfig.xml ③log4j2.xml ④spring-mybatis.xml ⑤spring-context.xml ⑥spring-mvc.xml ⑦修改web.xml文件 二、逆向生成增删改查 2.1.导入相关u…

网络原理,了解xml, json,protobuffer的特点

目录 外卖服务器场景带入 大佬们通用的规范格式 一、&#x1f466; 外卖服务器场景 外面服务器沟通有很多模式——展示商家列表等等&#xff0c;只是其中一个&#xff0c;因此需要一个统一的规划了——不同应用程序&#xff0c;里面的自定义格式是不一样的&#xff0c;这样的…

基于微服务+Java+Spring Cloud +UniApp +MySql开发的智慧工地源码(物联网、人工智能、AI识别、危大工程)

智慧工地系统利用物联网、人工智能、云计算、大数据、移动互联网等新一代信息技术&#xff0c;通过工地中台、三维建模服务、视频AI分析服务等技术支撑&#xff0c;实现智慧工地高精度动态仿真&#xff0c;趋势分析、预测、模拟&#xff0c;建设智能化、标准化的智慧工地综合业…

LeetCode 49题: 字母异位词分组

题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat&qu…

maven聚合工程的创建

父工程&#xff1a; parent-project 子工程&#xff1a;project-child project-child2 project-child3 创建父工程 将src目录删除了(在父工程中的src目录是没有用的&#xff09; 创建子工程 右击父工程------new------module 聚合工程创建完之后 在父工程的pom文件中 …

IJ中PHP环境的搭建和使用教程

目录 目录 前言 思维导图 1&#xff0c;PHP环境下载 1.下载链接 2.进行安装 3,自定义路径 4.进行相关的一些库的选择下载 2&#xff0c;进行IJ中PHP环境的配置 2.1,下载PHP插件 2.2,下载过程中的注意事项 3&#xff0c;为什么这么做呢? 3.1,原因 3.2,进行代码…

【Java 基础篇】Java List 使用指南:深入解析列表操作

Java 是一门强大的编程语言&#xff0c;拥有丰富的数据结构和集合类&#xff0c;其中之一就是 List 列表。List 是 Java 集合框架中的一个重要接口&#xff0c;它允许我们以有序、可重复的方式存储一组元素。本篇博客将从基础到高级&#xff0c;详细介绍 Java 中的 List 接口以…

Vulnhub系列靶机---HarryPotter-Aragog-1.0.2哈利波特系列靶机-1

文章目录 方式一信息收集主机发现端口扫描目录扫描wpscan工具 漏洞利用msf工具数据库权限用户权限root提权 方式二信息收集gobuster扫描wpscan扫描 漏洞利用POC 靶机文档&#xff1a;HarryPotter: Aragog (1.0.2) 下载地址&#xff1a;Download (Mirror) 方式一 信息收集 主机…

入门人工智能 —— 学习条件语句、循环语句、使用 Python 的数据结构来存储和组织数据,例如列表、字典、集合(3)

入门人工智能 —— 学习条件语句、循环语句、使用 Python 的数据结构来存储和组织数据,例如列表、字典、集合 1. 条件语句&#xff08;Conditional Statements&#xff09;2. 循环语句&#xff08;Loop Statements&#xff09;使用 for 循环&#xff1a;使用 while 循环&#x…

Spring Cache:提高应用性能的策略和技巧

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Java项目基于SpringBoot藏区特产销售系统,可作为毕业设计

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 今天为大家带来的是基于 Java SpringBootVue 的藏区特产销售系统 文章目录 1. 简介2.主要技术3 功能分析4 系…

Python超入门(3)__迅速上手操作掌握Python

# 11.if语句 is_student True # bool类型 is_teacher Falseif is_student:print("请到操场集合") elif is_teacher:print("请到办公室集合") else:print("请离开学校") print("谢谢合作") """ 请到操场集合 谢谢合…

javaee springMVC的简单使用 jsp页面在webapp和web-inf目录下的区别

项目结构 依赖文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/…

【网络编程】学习成果day7:用sqlite3和fgetc将字典写入数据库中的数据表。

1.将字典写入数据库中的数据表 代码&#xff1a; linuxlinux:~/study/NETbc$ cat 03_dictsqlite3.c #include<myhead.h> #define MAX 50int do_insert(sqlite3* db);int main(int argc, const char *argv[]) {//打开数据库sqlite3 *dbNULL;if(sqlite3_open("./dic…

【补】代码随想录算法训练营day38|动态规划 |509. 斐波那契数|70. 爬楼梯|746. 使用最小花费爬楼梯

动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#xff0c;贪心没有状态推…