【C++】AVL树(平衡二叉树)

目录

  • 一、AVL树的定义
  • 二、AVL树的作用
  • 三、AVL树的插入操作
    • 插入——平衡因子的更新
    • 插入——左单旋
    • 插入——右单旋
    • 插入——左右双旋
    • 插入——右左双旋
  • 四、ALVL树的验证
  • 五、AVL树的性能

一、AVL树的定义

AVL树,全称 平衡二叉搜索(排序)树

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

平衡因子(Balance Factor,简写为bf)
平衡因子(bf):结点的左子树的深度减去右子树的深度。也可以是右子树的深度减去左子树的深度。看个人实现而异。

即: 结点的平衡因子 = 左子树的高度 - 右子树的高度。
或者 节点的平衡因子 = 右子树的高度 - 左子树的高度。

AVL树本质上是一颗二叉查找树,但是它又具有以下特点:

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

这就是一颗AVL树
在这里插入图片描述

二、AVL树的作用

有一颗二叉树,他有n个节点,如果他是一颗二叉搜索树,他形状多样,可能会形成单枝树,高度为n,那么在这颗搜索树中查找元素的最坏时间复杂度为O(n),最好时间复杂度是O( l o g 2 n log_2 n log2n)。
如果他是一颗AVL树,他的高度稳定为 l o g 2 n log_2 n log2n,查找元素的时间复杂度为O( l o g 2 n log_2 n log2n)。在这里插入图片描述
由上图可知,同样的结点,由于插入方式不同导致树的高度也有所不同。特别是在带插入结点个数很多且正序的情况下,会导致二叉树的高度是O(N),而AVL树就不会出现这种情况,树的高度始终是O(lgN).高度越小,对树的一些基本操作的时间复杂度就会越小。这也就是我们引入AVL树的原因。

三、AVL树的插入操作

插入——平衡因子的更新

在插入一个元素的时候,必然会引起平衡因子的变化,所以我们需要在插入的时候把平衡因子同时更新,在平衡因子大于1或者小于-1时,我们则需要进行旋转操作,进行调整,使平衡因子再次正常,从而保证这颗二叉树一直是一颗AVL树。

使用平衡因子计算: 右子树高度 - 左子树高度

情况一:
在这里插入图片描述
在插入元素后,需要更新父节点的平衡因子,在父节点的左子树插入元素,父节点的平衡因子-1,在父节点的左子树插入元素,父节点的平衡因子+1,如果父节点的平衡因子更新过后变为1或者-1,则需继续往上更新至根节点,因为1或者-1表示该节点的高度发生改变,需往上更新。

情况2:
在这里插入图片描述
在插入元素后,需要更新父节点的平衡因子,在父节点的左子树插入元素,父节点的平衡因子-1,在父节点的左子树插入元素,父节点的平衡因子+1,如果父节点的平衡因子更新过后变为0,则不需要继续向上更新,因为变为0只能说明该树高度没有变化,只是相对于原来变得平衡。

如果在更新平衡因子后,平衡因子不在(-1/0/1)范围时,则需旋转操作,下面讲解如何进行旋转操作

由于插入需要旋转的情况较多,大致可以分为四大类

插入——左单旋

动图演示
请添加图片描述

情况一
右子树高时,在右子树的右侧插入元素,此时需要左单旋这里是引用

插入——右单旋

动图演示
请添加图片描述

情况二、
左子树较高时,在左子树的左侧插入元素,此时需要右单旋这里是引用

插入——左右双旋

情况三、左子树较高时,在左子树的右侧插入元素,此时需要左右双旋,即:先对30进行左单旋,然后再对90进行右单旋这里是引用

插入——右左双旋

情况四、右子树较高时,在右子树的左侧插入元素,此时需要右左双旋,即:先对90进行右单旋,然后再对30进行左单旋
在这里插入图片描述

四、ALVL树的验证

int _Height(Node* root)
{
	//用来计算二叉树的高度
	if (root == NULL)
		return 0;
	int leftH = _Height(root->_left);
	int rightH = _Height(root->_right);
 
	return leftH > rightH ? leftH + 1 : rightH + 1;
}
 
bool _IsBalance(Node* root)
{
	if (root == NULL)
		return true;
	int leftH = _Height(root->_left);
	int rightH = _Height(root->_right);
 	
 	//检查平衡因子
	if (rightH - leftH != root->_bf)
	{
		cout << root->_kv.first << "节点平衡因子异常" << endl;
		return false;
	}
 	//通过计算左右子树的高度差判断这颗二叉树是否为AVL树
	return abs(leftH - rightH) < 2
		&& _IsBalance(root->_left)
		&& _IsBalance(root->_right);
		//检查高度差要检查二叉树中所有节点的左右子树的高度差
}
 
bool IsBalance()
{
	return _IsBalance(_root);
}

五、AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 l o g 2 n log_2 n log2n

但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

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

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

相关文章

使用SpringBoot + Thymeleaf 完成简单的用户登录

&#x1f600;前言 本篇博文是关于Thymeleaf 的综合案例&#xff0c; 使用SpringBoot Thymeleaf 完成简单的用户登录-列表功能&#xff0c;希望你能够喜欢&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨…

​Kubernetes的演变:从etcd到分布式SQL的过渡

DevRel领域专家Denis Magda表示&#xff0c;他偶然发现了一篇解释如何用PostgreSQL无缝替换etcd的文章。该文章指出&#xff0c;Kine项目作为外部etcd端点&#xff0c;可以将Kubernetes etcd请求转换为底层关系数据库的SQL查询。 受到这种方法的启发&#xff0c;Magda决定进一步…

Cat(5):API介绍—Event

Event 用来记录一件事发生的次数&#xff0c;比如记录系统异常&#xff0c;它和transaction相比缺少了时间的统计&#xff0c;开销比transaction要小。 Cat.logEvent 记录一个事件。 Cat.logEvent("URL.Server", "serverIp", Event.SUCCESS, "ip${…

如何进行远程debug?

文章目录 前言一、使用步骤1.首先通过nohup在启动jar包的我们可以添加参数&#xff1a;2.具体参数的含义如下&#xff1a;3. 查询监听的端口&#xff1a; 前言 在工作中&#xff0c;排查问题我们经常需要进行debug&#xff0c;而远程debug能够方便的帮助我们排查线上的问题。 …

【力扣】496. 下一个更大元素 I <单调栈、模拟>

【力扣】496. 下一个更大元素 I nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。给你两个没有重复元素的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#xff0c;其中nums1 是 nums2 的子集。   对于每个 0 < i <…

【AIGC】 国内版聊天GPT

国内版聊天GPT 引言一、国内平台二、简单体验2.1 提问2.2 角色扮演2.3 总结画图 引言 ChatGPT是OpenAI发开的聊天程序&#xff0c;功能强大&#xff0c;可快速获取信息&#xff0c;节省用户时间和精力&#xff0c;提供个性化的服务。目前国产ChatGPT&#xff0c;比如文心一言&a…

Kubernetes二进制部署方案

目录 一、环境准备 2.1、主机配置 2.2、安装 Docker 2.3、生成通信加密证书 2.3.1、生成 CA 证书&#xff08;所有主机操作&#xff09; 2.3.2、生成 Server 证书&#xff08;所有主机&#xff09; 2.3.3、生成 admin 证书(所有主机) 2.3.4、生成 proxy 证书 三、部署 …

JMeter接口自动化测试实例—JMeter引用javaScript

Jmeter提供了JSR223 PreProcessor前置处理器&#xff0c;通过该工具融合了Java 8 Nashorn 脚本引擎&#xff0c;可以执行js脚本以便对脚本进行前置处理。其中比较典型的应用就是通过执行js脚本对前端数据进行rsa加密&#xff0c;如登录密码加密。但在这里我就简单的应用javaScr…

java练习6. 求完数

题目: 请编程求出1000 以内的所有完数。 完数:一个数如果恰好等于它的所有真因子&#xff08;即除了自身外的所有因数&#xff09;之和&#xff0c;这个数就称为"完数"。 public static void main(String[] args) {for (int i 2; i < 1000; i) {int sum0;for (in…

ARM M33架构入门

概述 Arm Cortex-M33核心处理器专为需要高效安全或数字信号控制的物联网和嵌入式应用而设计。该处理器具有许多可选功能&#xff0c;包括数字信号处理扩展 (DSP)、用于硬件强制隔离的TrustZone 安全性、内存保护单元 (MPU)和浮点单元 (FPU)。 Cortex-M33 的性能比 Cortex-M…

【笔试题心得】关于正则的一些整理

本文部分内容摘抄整理自 正则表达式 – 教程 | 菜鸟教程 在笔试的过程中&#xff0c;也常常会对正则表达式进行考察&#xff0c;这里对正则表达式的常见用法&#xff0c;做一个学习和总结。 正则表达式的模式可以包括以下内容&#xff1a; 字面值字符&#xff1a;例如字母、数…

使用 Visual Studio GoogleTest编写 C/C++ 单元测试——入门篇

入门教程 Visual Studio 新建 GoogleTest项目&#xff0c;一路选默认参数 pch.h #pragma once#include "gtest/gtest.h"int add(int a, int b);pch.cpp #include "pch.h"int add(int a, int b) {return a b; }test.cpp #include "pch.h"TES…

Mac平台最佳PDF编辑软件,Qoppa PDF Studio Pro助您实现PDF文件的完美编辑

Qoppa PDF Studio Pro是一款功能强大的PDF编辑软件&#xff0c;现已推出Mac版本&#xff01;无论是个人用户还是企业用户&#xff0c;都能够从中受益。 Qoppa PDF Studio Pro为用户提供了一系列丰富的编辑工具&#xff0c;可以轻松地对PDF文件进行编辑、注释和标记。 用户可以…

【PACS源码】认识PACS的架构和工作流程

&#xff08;一&#xff09;PACS系统的组成及架构 PACS系统的基本组成部分包括&#xff1a;数字影像采集、通讯和网络、医学影像存储、医学影像管理、各类工作站五个部分。 而目前PACS系统的软件架构选型上看&#xff0c;主要有C/S和B/S两种形式。 C/S架构&#xff0c;即Client…

大数据平台是什么意思?有什么用?一般包含哪些模块?

大数据时代&#xff0c;还有很多人不知道大数据平台是什么意思&#xff1f;有什么用&#xff1f;一般包含哪些模块&#xff1f;今天我们就一起来简单了解一下吧&#xff01;仅供参考哦&#xff01; 大数据平台是什么意思&#xff1f;有什么用&#xff1f;一般包含哪些模块&am…

Java 项目日志实例基础:Log4j

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ 介绍几个日志使用方面的基础知识。 1 Log4j 1、Log4j 介绍 Log4j&#xff08;log for java&#xff09;是 Apache 的一个开源项目&#xff0c;通过使用 Log4j&#xff0c;我…

Visual Studio 2019源码编译cpu版本onnxruntime

1.下载onnxruntime源码 源码地址&#xff1a;gitee 》https://gitee.com/mirrors/onnx-runtime github 》https://github.com/microsoft/onnxruntime git clone --recursive https://gitee.com/mirrors/onnx-runtime 2.安装anaconda并配置python环境 安装anaconda时记得勾选默…

【C++深入浅出】初识C++中篇(引用、内联函数)

目录 一. 前言 二. 引用 2.1 引用的概念 2.2 引用的使用 2.3 引用的特性 2.4 常引用 2.5 引用的使用场景 2.6 传值、传引用效率比较 2.7 引用和指针的区别 三. 内联函数 3.1 内联函数的概念 3.2 内联函数的特性 一. 前言 上期说道&#xff0c;C是在C的基础之上&…

常见前端基础面试题(HTML,CSS,JS)(三)

JS 中如何进行数据类型的转换&#xff1f; 类型转换可以分为两种&#xff0c;隐性转换和显性转换 显性转换 主要分为三大类&#xff1a;数值类型、字符串类型、布尔类型 三大类的原始类型值的转换规则我就不一一列举了 数值类型&#xff08;引用类型转换&#xff09; Numbe…

广度优先遍历与最短路径(Java 实例代码源码包下载)

目录 广度优先遍历与最短路径 Java 实例代码 src/runoob/graph/ShortestPath.java 文件代码&#xff1a; 广度优先遍历与最短路径 广度优先遍历从某个顶点 v 出发&#xff0c;首先访问这个结点&#xff0c;并将其标记为已访问过&#xff0c;然后顺序访问结点v的所有未被访问…