AVL树-详细解析【数据结构】

AVL树是首个被发明的自平衡二叉查找树,在1962年由两位苏联科学家G.M. Adelson-Velsky和E.M. Landis提出。AVL树得名于发明者的首字母。在AVL树中,任何节点的两个子树的高度最大差别为一,确保了树的平衡度,使得查找操作相比于普通的二叉查找树更加高效。

AVL树的性质

AVL树保持了二叉查找树的基础性质,即对于任何一个节点,其左子树上的所有节点的值都小于该节点的值,右子树所有节点的值都大于该节点的值。此外,AVL树增加了以下平衡条件:

  • 平衡因子: AVL树中的每个节点的平衡因子被定义为左子树的高度减去右子树的高度(有些定义为相反)。给定的每个节点的平衡因子必须是-1、0或1。

这种强制的平衡条件确保树的最坏情况下的高度为O(log n),其中n是树中节点的数量,从而也保证了查找/插入/删除操作都可以在对数时间内完成。

AVL树的旋转操作

保持AVL树平衡的主要机制是通过旋转操作,分为四种基本旋转:

  1. LL(左左)旋转: 当在节点的左子树的左侧插入导致不平衡时进行。通过一个右旋转来平衡树。

  2. RR(右右)旋转: 当在节点的右子树的右侧插入导致不平衡时进行。通过一个左旋转来平衡树。

  3. LR(左右)旋转: 当在节点的左子树的右侧插入导致不平衡时进行。首先在导致失衡节点的左子树上进行左旋转,然后对该节点进行右旋转。

  4. RL(右左)旋转: 当在节点的右子树的左侧插入导致不平衡时进行。首先在导致失衡节点的右子树上进行右旋转,然后对该节点进行左旋转。

这些旋转能够在维持二叉查找树的性质的同时回复AVL树特有的平衡性质。

AVL树的插入操作

向AVL树插入一个新的节点大体分为三步:

  1. 常规二叉搜索树插入: 首先按照二叉搜索树的规则将节点插入正确位置。

  2. 更新平衡因子: 从插入点开始,向上遍历回根节点,更新祖先节点的平衡因子。

  3. 重新平衡(如果必要): 如果在更新过程中某个节点的平衡因子变为非-1、0或1,将对该节点进行一次或多次旋转操作以恢复平衡。这可能涉及上述四种旋转中的任何一种或复合旋转。

AVL树的删除操作

从AVL树中删除一个节点包括了以下步骤:

  1. 常规二叉搜索树删除: 遵循二叉搜索树的规则,找到并删除该节点,这可能涉及将节点与其直接后继互换的操作。

  2. 更新平衡因子: 从删除节点的父节点开始,向上遍历到根节点,更新节点的平衡因子。

  3. 重新平衡(如果必要): 如果在更新过程中某个节点的平衡因子不是-1、0或1,将对该节点执行相应的旋转操作恢复平衡。

删除操作要复杂些,因为可能需要在不同层上多次进行平衡调整。

深度分析

AVL树的设计主旨是维持二叉查找树在动态更新操作下的平衡,从而避免性能恶化。为了保持深入的讨论,我们将分别撷取关键方面进行详尽的分析。

平衡因子计算

AVL树中每个节点N都有一个平衡因子(BF),它是根据以下公式定义的:

平衡因子(BF) = 高度(左子树) - 高度(右子树)

常规情况下,左子树或右子树的高度的计算是从当前节点向下递归到叶子节点,计算最长路径上边的数量,叶子节点的高度定义为0。因此:

  • BF = 0 表示左子树和右子树的高度相同。
  • BF = -1 表示右子树比左子树高1层。
  • BF = 1 表示左子树比右子树高1层。

AVL树要求所有节点的平衡因子绝对值必须小于或等于1。每次插入或删除操作后,都需要更新从影响节点到根节点路径上所有节点的平衡因子,并进行相应的旋转操作以恢复平衡性。

旋转操作

旋转是用来恢复AVL树平衡的一种操作。在不同的情形下,可能需要不同种类的旋转操作:

LL旋转

当一个节点N的左子树的左边产生了一个新节点,并造成不平衡时,会进行LL旋转。以下是LL旋转的步骤:

  1. 设N为失衡节点,L为N的左子节点。
  2. 将L的右子树移动成N的左子树。
  3. 将N变成L的右子树。
RR旋转

这是LL的镜像操作,当一个节点N的右子树的右边产生了一个新节点,并造成不平衡时,会进行RR旋转。以下是RR旋转的步骤:

  1. 设N为失衡节点,R为N的右子节点。
  2. 将R的左子树移动成N的右子树。
  3. 将N变成R的左子树。
LR旋转

当一个节点N的左子树的右边产生了一个新节点,并造成不平衡时,会进行LR旋转。LR旋转首先进行L的RR旋转,然后对N进行LL旋转。

  1. 设N为失衡节点,L为N的左子节点,LR为L的右子节点。
  2. 对L进行RR旋转。
  3. 对N进行LL旋转。
RL旋转

这是LR旋转的镜像,当一个节点N的右子树的左边产生了一个新节点,并造成不平衡时,会进行RL旋转。

  1. 设N为失衡节点,R为N的右子节点,RL为R的左子节点。
  2. 对R进行LL旋转。
  3. 对N进行RR旋转。

插入操作

插入操作可以概括为以下步骤:

  1. 插入新节点X,像在常规二叉查找树中那样。
  2. 更新从X到根节点的路径上所有节点的平衡因子。
  3. 检查这些节点的平衡因子,如果发现任何节点的平衡因子变为2或-2,那么从最低的不平衡点开始进行旋转操作来恢复平衡。

伪代码示例:

function insert(node, value)if node == nullreturn newNode(value)if value < node.valuenode.left = insert(node.left, value)else if value > node.valuenode.right = insert(node.right, value)elsereturn node// 更新节点的高度node.height = 1 + max(height(node.left), height(node.right))// 获取平衡因子balance = getBalance(node)// 平衡if balance > 1 and value < node.left.valuereturn rightRotate(node)if balance < -1 and value > node.right.valuereturn leftRotate(node)if balance > 1 and value > node.left.valuenode.left = leftRotate(node.left)return rightRotate(node)if balance < -1 and value < node.right.valuenode.right = rightRotate(node.right)return leftRotate(node)return node

删除操作

删除操作遵循以下步骤:

  1. 在树中定位并删除指定节点。
  2. 更新从删除节点的父节点到根节点的路径上所有节点的平衡因子。
  3. 对失去平衡的节点进行旋转操作,恢复平衡。

伪代码示例:

function deleteNode(root, value)// STEP 1: PERFORM STANDARD BST DELETEif root == nullreturn rootif value < root.valueroot.left = deleteNode(root.left, value)else if value > root.valueroot.right = deleteNode(root.right, value)else// node with only one child or no childif (root.left == null) or (root.right == null)temp = nullif temp == root.lefttemp = root.rightelsetemp = root.leftif temp == null // No child casetemp = rootroot = nullelse // One child caseroot = temp // Copy the contents of the non-empty childelse// node with two children: Get the inorder successortemp = minValueNode(root.right)root.value = temp.valueroot.right = deleteNode(root.right, temp.value)if root == nullreturn root// STEP 2: UPDATE HEIGHT OF THE CURRENT NODEroot.height = max(height(root.left), height(root.right)) + 1// STEP 3: GET THE BALANCE FACTOR OF THIS NODEbalance = getBalance(root)// If this node becomes unbalanced, then there are 4 cases// Left Left Caseif balance > 1 and getBalance(root.left) >= 0return rightRotate(root)// Left Right Caseif balance > 1 and getBalance(root.left) < 0root.left = leftRotate(root.left)return rightRotate(root)// Right Right Caseif balance < -1 and getBalance(root.right) <= 0return leftRotate(root)// Right Left Caseif balance < -1 and getBalance(root.right) > 0root.right = rightRotate(root.right)return leftRotate(root)return root

操作效率分析

由于AVL树的严格平衡特性,插入和删除操作可能要求多次旋转,这增加了操作的复杂性。尽管如此,由于树的高度被严格控制在O(log n),因此插入和删除操作的最坏情况时间复杂度为O(log n)。实际的旋转操作仅涉及改变节点几个指针,因此可以认为是O(1)操作,不过这会在插入或删除后沿着路径向上逐步进行,因此总的旋转成本是O(log n)。由于我们只会在最坏的情况下沿着路径上旋转一次,所以这样的成本是可以接受的。

不同旋转操作情景的剖析

旋转操作虽然以四类基本操作来定义,但是每种操作对树的结构和平衡因子都有不同的影响。例如,LL旋转是对树的一边性质最直接的补救,它通过一次简单的旋转即可恢复平衡。而LR旋转则涉及到两个步骤,首先是对失衡节点的左子节点进行RR旋转,然后对失衡节点本身进行LL旋转。这意味着在执行LR旋转时,我们需要更新不仅是失衡节点,同时也要更新其左子节点及LR节点的平衡因子。从逻辑上讲,LR旋转处理的是两种不平衡因子的组合,因此在理解和实现时需要更多的注意。

AVL树的维护需要对树的结构和旋转操作有深刻的理解。每次插入和删除操作后都可能要求维护这种平衡,而这种保持平衡的要求是AVL树能够保持其性能特点的根本。

如果你想更深入地了解人工智能的其他方面,比如机器学习、深度学习、自然语言处理等等,也可以点击这个链接,我按照如下图所示的学习路线为大家整理了100多G的学习资源,基本涵盖了人工智能学习的所有内容,包括了目前人工智能领域最新顶会论文合集和丰富详细的项目实战资料,可以帮助你入门和进阶。

链接: 人工智能交流群【最新顶会与项目实战】(点击跳转)

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023 亚马逊云科技 re:Invent 大会探秘:Aurora 无限数据库的突破性应用

文章目录 一、前言二、Amazon Aurora 无限数据库2.1 亚马逊云科技数据库产品发展历程2.2 什么是 Amazon Aurora Limitless Database&#xff08;无限数据库&#xff09;2.3 Amazon Aurora Limitless Database 设计架构2.4 Amazon Aurora Limitless Database 分片功能2.5 使用 A…

微服务最佳实践:构建可扩展且高效的系统

微服务架构彻底改变了现代软件开发&#xff0c;提供了无与伦比的敏捷性、可扩展性和可维护性。然而&#xff0c;有效实施微服务需要深入了解最佳实践&#xff0c;以充分发挥微服务的潜力&#xff0c;同时避免常见的陷阱。在这份综合指南中&#xff0c;我们将深入研究微服务的关…

WEB 3D技术 简述React Hook/Class 组件中使用three.js方式

之前 已经讲过了 用vue结合three.js进行开发 那么 自然是少不了react 我们 还是先创建一个文件夹 终端执行 npm init vitelatest输入一下项目名称 然后技术选择 react 也不太清楚大家的基础 那就选择最简单的js 然后 我们就创建完成了 然后 我们用编辑器打开创建好的项目目…

wvp-GB28181-pro 2.0+ZLMediaKit 使用Dockerfile制作镜像以及部署【CentOS7】

说明 部署gb28181和zlm主要需要构建两个镜像&#xff0c;第一个为基础镜像&#xff0c;以centos7为基础构建新的基础镜像base.Dockerfile,第二个镜像为服务部署镜像server.Dockerfile&#xff0c;以第一个镜像base.Dockerfile构建出的镜像为基础镜像进行构建 整个基础镜像的构…

高效营销系统集成:百度营销的API无代码解决方案,提升电商与广告效率

百度营销API连接&#xff1a;构建无代码开发的高效集成体系 在数字营销的高速发展时代&#xff0c;企业追求的是快速响应市场的能力以及提高用户运营的效率。百度营销API连接正是为此而生&#xff0c;它通过无代码开发的方式&#xff0c;实现了电商平台、营销系统和CRM的一站式…

深度解读 Cascades 查询优化器

数据库中查询优化器是数据库的核心组件&#xff0c;其决定着 SQL 查询的性能。Cascades 优化器是 Goetz 在 volcano optimizer generator 的基础上优化之后诞生的一个搜索框架。 本期技术贴将带大家了解 Cascades 查询优化器。首先介绍 SQL 查询优化器&#xff0c;接着分析查询…

集群监控Zabbix和Prometheus

文章目录 一、Zabbix入门概述1、Zabbix概述2、Zabbix 基础架构3、Zabbix部署3.1 前提环境准备3.2 安装Zabbix3.3 配置Zabbix3.4 启动停止Zabbix 二、Zabbix的使用与集成1、Zabbix常用术语2、Zabbix实战2.1 创建Host2.2 创建监控项&#xff08;Items&#xff09;2.3 创建触发器&…

Kubernetes实战(十四)-k8s高可用集群扩容master节点

1 单master集群和多master节点集群方案 1.1 单Master集群 k8s 集群是由一组运行 k8s 的节点组成的&#xff0c;节点可以是物理机、虚拟机或者云服务器。k8s 集群中的节点分为两种角色&#xff1a;master 和 node。 master 节点&#xff1a;master 节点负责控制和管理整个集群…

机器学习--归一化处理

归一化 归一化的目的 归一化的一个目的是&#xff0c;使得梯度下降在不同维度 θ \theta θ 参数&#xff08;不同数量级&#xff09;上&#xff0c;可以步调一致协同的进行梯度下降。这就好比社会主义&#xff0c;一小部分人先富裕起来了&#xff0c;先富带后富&#xff0c…

Crocoddyl: 多接触最优控制的高效多功能框架

系列文章目录 前言 我们介绍了 Crocoddyl&#xff08;Contact RObot COntrol by Differential DYnamic Library&#xff09;&#xff0c;这是一个专为高效多触点优化控制&#xff08;multi-contact optimal control&#xff09;而定制的开源框架。Crocoddyl 可高效计算给定预定…

jmeter 如何循环使用接口返回的多值?

有同学在用jmeter做接口测试的时候&#xff0c;经常会遇到这样一种情况&#xff1a; 就是一个接口请求返回了多个值&#xff0c;然后下一个接口想循环使用前一个接口的返回值。 这种要怎么做呢&#xff1f; 有一定基础的人&#xff0c;可能第一反应就是先提取前一个接口返回…

CCD相机为什么需要积分球均匀光源

积分球内腔是一个具备高漫反射特性的收光球&#xff0c;其内部中空、内球面均匀地涂有漫反射材料&#xff0c;具有匀光与混光的作用&#xff0c;因此常常被用来做收光的均光球。由于光源性能等因素的影响&#xff0c;可能导致出射光线带偏振方向、出光不均匀&#xff0c;使用积…

智能优化算法应用:基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于静电放电算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.静电放电算法4.实验参数设定5.算法结果6.…

MongoDB表的主键可以重复?!MongoDB的坑

MongoDB表的主键可以重复&#xff1f;&#xff01; 眼见为实&#xff1f; 碰到一个奇怪的现象&#xff0c; MongoDB的一个表居然有两个一样的_id值&#xff01; 再次提交时&#xff0c;是会报主键冲突的。那上图&#xff0c;为什么会有两个一样的_id呢&#xff1f; 将它们的…

盛最多水的容器

给定一个长度为 n 的整数列表 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例1&…

@Scheduled任务调度/定时任务-非分布式

1、功能概述 任务调度就是在规定的时间内执行的任务或者按照固定的频率执行的任务。是非常常见的功能之一。常见的有JDK原生的Timer, ScheduledThreadPoolExecutor以及springboot提供的Schduled。分布式调度框架如QuartZ、Elasticjob、XXL-JOB、SchedulerX、PowerJob等。 本文…

MySQL之DQL语句

文章目录 DQL语句指定查询查询全部查询部分数据别名查询使用order by子句拼接查询去重查询WHERE – 条件过滤模糊查询JOIN – 多表关联求和查询排序查询统计查询分页查询 DQL语句 DQL&#xff08;Data Query Language&#xff09;查询数据 操作查询&#xff1a;select简单的查…

Cell Systems | 深度学习开启蛋白质设计新时代

今天为大家介绍的是来自Bruno Correia团队的一篇综述。深度学习领域的迅速进步对蛋白质设计产生了显著影响。最近&#xff0c;深度学习方法在蛋白质结构预测方面取得了重大突破&#xff0c;使我们能够得到数百万种蛋白质的高质量模型。结合用于生成建模和序列分析的新型架构&am…

OpenCV开发:MacOS源码编译opencv,生成支持java、python、c++各版本依赖库

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它为开发者提供了丰富的工具和函数&#xff0c;用于处理图像和视频数据&#xff0c;以及执行各种计算机视觉任务。 以下是 OpenCV 的一些主要特点和功能&#xff…

二、如何保证架构的质量、架构前期准备、技术填补与崩溃预防、系统重构

1、如何保证架构的质量 -- 稳定性和健壮性 2、正确的选择是良好的开端 -- 架构前期准备 ① 架构师分类&#xff1a;系统架构师、应用架构师、业务架构师 3、技术填补与崩溃预防 4、系统重构