当前位置: 首页 > news >正文

数据结构-AVL树

目录

二叉树

二叉搜索树的查找方式:

AVL树

AVL树节点的实现

AVL树节点的插入操作

AVL树的旋转操作

右旋转:

左旋转:

左右双旋:

右左双旋:

AVL树的不足和下期预告(红黑树)


二叉树

了解AVL树之前,需要先了解一下二叉搜索树的概念,二叉搜索树具有以下性质:

1,如果左子树不为空,则左子树上所有节点的值都小于跟节点的值。

2,如果右子树不为空,则右子树的所有节点的值都大于跟节点的值。

3,根节点的左右子树也是一颗二叉搜索树。

如果使用二叉树的中序遍历方法来遍历一颗二叉树,则可以得到一个有序的序列。

二叉搜索树的查找方式:

根据上图可以对二叉树进行查找从而得到我们想要的节点。

一个完全二叉树的查找效率可以达到 O(log N) 级别,但如果我们插入的数值都是大于根节点的数值,并且是严格递增的,那么此时整个二叉树就会退化成一个链表的结构,那么此时查找的效率也会退化成O(N)。因此我们就需要考虑一个问题,无论何时进行插入,都可以让二叉树,保持左右子树的相对平衡,随时更改根节点,这样就可以让查找的时间复杂度一直保持在O(log N),所以研究者引入了AVL树的概念。

AVL树

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。

AVL树它本质上其实还是一个二叉树,它的特点符合二叉树的所有特点,在此之外,AVL树还具有平衡的性质,也就是说,它的左子树和右子树的高度差的绝对值不会大于1,因此这样也就保证了AVL树的查找效率。

AVL树节点的实现

为了实现AVL树,我们需要先定义树的节点,和普通的二叉树不同,在定义节点的时候,我们也需要在其中定义一个平衡因子,我们使用bf(balance factor)来表示:AVL树的节点定义如下:

class TreeNode{//定义树的左右节点索引和父亲索引public TreeNode left = null;public TreeNode right = null;public TreeNode parent = null;public int val;public int bf;//定义构造函数public TreeNode (int val){this.val = val;}
}

我们定义当前节点的平衡因子 = 右树的高度 - 左树的高度。如果当前节点的bf<0,那么左树就高,bf>0右树就高。bf = 0,那么两边一样高。当然这只是其中的一种实现方式而已(本文是这么定义的)。

AVL树节点的插入操作

首先,我们将其分为两步

1,按照二叉树的插入方式进行插入。

2,对不满足条件的节点进行旋转,使树达到平衡。

此时可以看下接下来这几幅图:

假设我要在二叉树种插入一个值为100,那么此时我应该找到100应该插入到哪个位置,每一次寻找定义cur为要插入的位置,定义parent为cur的父亲节点,那么遍历下来就可以找到插入的位置,此时代码如下:

    public TreeNode root ;public void insert(int val){//1,首先先进行节点的插入操作;TreeNode node = new TreeNode(val);if(this.root == null){//如果树为空,那么node就是新的rootthis.root = node;}else{TreeNode parent = null;TreeNode cur = this.root;// 1.1 先判断要插入的位置,然后再进行插入while(cur != null){if(cur.val < val){parent = cur;cur = cur.right;} else if (cur.val == val) {return;}else{parent = cur;cur = cur.left;}}//此时找到了要插入的位置,对node进行插入,插入的位置为parent所指向的节点//判断往左边插入还是右边插入,然后再让node指回去。if(parent.val < val){parent.right = node;}else{parent.left = node;}node.parent = parent;cur = node;}}

一定要让node指向指回去,否则子节点会丢失父节点的索引。

AVL树的旋转操作

基于以上的插入,我们可以发现一个问题,就是说,如果每次都插入比上一次大的值,那么势必会让这个树退化成一个链表,那么此时树的存储结构优势将会丢掉,所以AVL树引入了旋转操作来对树进行操作。从而使得这棵树不会退化成链表。

cur插入后,parent的平衡因子一定需要调整,

在插入之前,parent的平衡因子分为三种情况:-1,0, 1

插入时分以下两种情况:  

1. 如果cur插入到parent的左侧,只需给parent的平衡因子 -1 即可  

2. 如果cur插入到parent的右侧,只需给parent的平衡因子 +1 即可  

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

1. 如果parent的平衡因子为0,说明插入之前parent的平衡因子为正负1,插入后被调整成0,此时满足AVL树的性质,插入成功

2. 如果parent的平衡因子为正负1,说明插入前parent的平衡因子为0,插入后被更新成正负1,此时以parent为根的树的高度增加,需要继续向上更新  

3. 如果parent的平衡因子为正负2,则parent的平衡因子违反平衡树的性质,需要对其进行旋转处理

此时更新操作就如下:

            while(){//更新parent的平衡因子if(cur == parent.right){parent.bf++;}else{parent.bf--;}//更新后的平衡因子为0,说明插入后的结果是平衡的,此时无需后续操作if(parent.bf == 0){return;}if(parent.bf != 1 && parent.bf != -1){//此时需要继续向上更新if(parent.bf == 2){if(cur.bf == 1){// parent.bf == 2 cur.bf == 1}else{// parent.bf == 2 cur.bf == -1}}else{if(cur.bf == 1){// parent.bf == -2 cur.bf == 1}else{// parent.bf == -2 cur.bf == -1}}}}

那么基于以上操作,我们的更新平衡因子的模板已经搭好了,但是在什么情况下需要进行旋转呢?

右旋转:

假设有上面这种情况,原来的cur.bf == 0 , 但是parent.bf == -1 ,此时在左树的最左边插入一个节点,那么此时的节点情况就变成了cur.bf == -1 , parent.bf == -2 。那么此时就需要对parent节点进行右旋转,从而调整树的结构。

此时需要注意以下几点:

 1.  30 节点的右孩子可能存在,也可能不存在。

 2.  60 可能是根节点,也可能是子树。如果是根节点,旋转完成后,要更新根节点     如果是子树,可能是某个节点的左子树,也可能是右子树。

在上图中可以看出,当我们想进行右转操作时,需要将parent.left 标记为 subL,将subL.right标记为subLR.

从2图转换为3图可以如上图表示:

1. 修改parent.left = subLR;

2. 修改subL.right = parent;

3. 修改 subLR.parent = parent (此时需要判断subLR是否为空

4. 保存parent的父亲节点(祖父节点)

5. 修改parent的父亲节点指向subL;

6. 修改祖父节点指向subL(需要确认祖父节点是否存在,如果不存在则parent是根节点

7. 修改subL.parent属性为祖父节点;

8. 判断完了之后还要修改平衡因子。

代码如下:

private void rotateRight(TreeNode parent) {TreeNode subL = parent.left;TreeNode subLR = subL.right;parent.left = subLR;subL.right = parent;if(subLR != null){subLR.parent = parent;}TreeNode pParent = parent.parent;parent.parent = subL;if(parent == this.root){this.root = subL;this.root.parent = null;}else{if(pParent.left == parent){pParent.left = subL;}else{pParent.right = subL;}subL.parent = pParent;}subL.bf = 0;parent.bf = 0;}

左旋转:

左旋转和右旋转的逻辑是一样的,不过是对称的操作。以下是左旋转的代码演示:

此时最初的parent的bf值为1,进行添加节点之后,则是会变成parent.bf 会变成2,此时的cur.bf

会变成1(因为给cur的右树增加了一层)。此时就需要用到左旋转的方法来进行旋转,从而降低AVL树的高度了。具体代码如下:和右旋转是对称的

 private void rotateLeft(TreeNode parent) {TreeNode subR = parent.right;TreeNode subRL = subR.left;parent.right = subRL;subR.left = parent;if(subRL != null){subRL.parent = parent;}TreeNode pParent = parent.parent;parent.parent = subR;if(parent == this.root){this.root = subR;this.root.parent = null;}else{if(pParent.left == parent){pParent.left = subR;}else{pParent.right =subR;}subR.parent = pParent;}subR.bf = parent.bf = 0;}

左右双旋:

 讲完了上述两种比较简单的情况,其实还有两种比较复杂的情况,比如说,

假如说是上面这种情况呢,此时我要插入的值为40,但是60节点bf更新为-2,此时的30这个节点的bf值为1,50节点bf值为-1,这时候单纯的旋转已经无法解决这些问题了。因此

此时先对30进行左旋转:可以得到50节点bf为-2,60节点 bf 为-2,30节点 bf 为 0

此时再对60节点进行右旋转:此时的50节点 bf 为 0 ,60节点bf为 1 此时的 AVL树已经达到了平衡。

private void rotateLR(TreeNode parent) {TreeNode subL = parent.left;TreeNode subLR = subL.right;int bf = subLR.bf;this.rotateRight(parent.left);this.rotateLeft(parent);if (bf == -1) {parent.bf = 1;subL.bf = 0;subLR.bf = 0;} else if (bf == 1) {subL.bf = -1;subLR.bf = 0;parent.bf = 0;}
}

右左双旋:

和左右双旋是对称的概念,此处便不再赘述了。

直接贴代码:

 private void rotateRL(TreeNode parent) {TreeNode subR = parent.right;TreeNode subRL = subR.left;int bf = subRL.bf;this.rotateRight(parent.right);this.rotateLeft(parent);if(bf == 1){parent.bf = -1;subR.bf = 0;subRL.bf = 0;} else if (bf == -1) {parent.bf = 0;subR.bf = 1;subRL.bf =0;}}

总之AVL树,就是为了让整个树不退化成链表,才引入的旋转机制。

AVL树的不足和下期预告(红黑树)

但是AVL树虽然保证了查询的效率,但是还是有一些机制上的问题,比如说,旋转非常消耗时间,比如我们在单旋的时候已经进行了8步操作,这只是其中的一次插入,当数据大量插入的时候AVL树显然是不够用的,因此科学家们又引入了红黑树的机制。下一次我会继续写关于红黑树的博客,希望大家能够多多点赞。

相关文章:

数据结构-AVL树

目录 二叉树 二叉搜索树的查找方式&#xff1a; AVL树 AVL树节点的实现 AVL树节点的插入操作 AVL树的旋转操作 右旋转&#xff1a; 左旋转&#xff1a; 左右双旋&#xff1a; 右左双旋&#xff1a; AVL树的不足和下期预告&#xff08;红黑树&#xff09; 二叉树 了…...

数字科技如何助力博物馆设计,强化文物故事表现力?

国际博物馆日是每年为了推广博物馆和文化遗产&#xff0c;而设立的一个特殊的日子&#xff0c;让我们可以深入探讨博物馆如何更好地呈现和保护我们的文化遗产&#xff0c;随着近年来的数字科技发展&#xff0c;其在博物馆领域的应用越来越广泛&#xff0c;它为博物馆提供了新的…...

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第七周) - 结构化预测

结构化预测 0. 写在大模型前面的话1. 词法分析 1.1. 分词1.2. 词性标注 2.2. 句法分析 2.3. 成分句法分析2.3. 依存句法分析 3. 序列标注 3.1. 使用分类器进行标注 4. 语义分析 0. 写在大模型前面的话 在介绍大语言模型之前&#xff0c;先把自然语言处理中遗漏的结构化预测补…...

5-Maven-setttings和pom.xml常用配置一览

5-Maven-setttings和pom.xml常用配置一览 setttings.xml配置 <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xs…...

input输入框设置样式

input清除自带样式 input, textarea,label, button,select,img,form,table,a{-webkit-tap-highlight-color: rgba(255,255,255,0);-webkit-tap-highlight-color: transparent;margin: 0;padding: 0;border: none; } /*去除iPhone中默认的input样式*/ input, button, select, t…...

平稳交付 20+ 医院,卓健科技基于 OpenCloudOS 的落地实践

导语&#xff1a;随着数字化转型于各个行业领域当中持续地深入推进&#xff0c;充当底层支撑的操作系统正发挥着愈发关键且重要的作用。卓健科技把 OpenCloudOS 当作首要的交付系统&#xff0c;达成了项目交付速度的提升、安全可靠性的增强、运维成本的降低。本文将会阐述卓健科…...

Python下载库

注&#xff1a;本文一律使用windows讲解。 一、使用cmd下载 先用快捷键win R打开"运行"窗口&#xff0c;如下图。 在输入框中输入cmd并按回车Enter或点确定键&#xff0c;随后会出现这个画面&#xff1a; 输入pip install 你想下载的库名&#xff0c;并按回车&…...

SAP HCM OPT函数作用

导读 INTRODUCTION OPT函数&#xff1a;SAP HCM工资核算是很多函数的汇总集&#xff0c;原有有兴趣问过SAP的人为什么SCHEMA需要这样设计&#xff0c;SAP的人说是用汇编的逻辑设计的&#xff0c;当时是尽可能用机器语言加速速度读取&#xff0c;每个函数都有对应的业务逻辑代码…...

Tensorflow音频分类

tensorflow https://www.tensorflow.org/lite/examples/audio_classification/overview?hlzh-cn 官方有移动端demo 前端不会 就只能找找有没有java支持 注意版本 注意JDK版本 package com.example.demo17.controller;import org.tensorflow.*; import org.tensorflow.ndarra…...

mqtt-emqx:keepAlive机制测试

mqtt keepAlive原理详见【https://www.emqx.com/zh/blog/mqtt-keep-alive】 # 下面开始写测试代码 【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2…...

C++基础7:STL六大组件

目录 一、标准容器 1、顺序容器 vector ​编辑 deque list 容器适配器 stack queue prority_queue: 关联容器 有序关联容器set、mutiset、map、mutimap 增删查O(log n) 无序关联容 unordered_set、unordered_mutiset、unordered_map、unordered_mutimap 增删…...

特别名词Test Paper1

特别名词Test Paper1 ability 能力abstract 摘要accountant 会计accuracy 准确度acid 酸action 行动activity 活动actor 男演员adult 成人adventure 冒险advertisements 广告&#xff0c;宣传advertising 广告advice 建议age 年龄agency 代理机构&#xff0c;中介agreement 同…...

每日题库:Huawe数通HCIA——全部【813道】

1.关于ARP报文的说法错误的是?单选 A.ARP报文不能被转发到其他广播域 B.ARP应答报文是单播方发送的 C.任何链路层协议都需要ARP协议辅助获取数据链路层标识 DARP请求报文是广播发送的 答案:C  解析: STP协议不需要ARP辅助 2.园区网络搭建时,使用以下哪种协议可以避免出现二层…...

#04 Stable Diffusion与其他AI图像生成技术的比较

文章目录 前言1. Stable Diffusion2. DALL-E3. GAN&#xff08;生成对抗网络&#xff09;4. VQ-VAE比较总结 前言 随着人工智能技术的飞速发展&#xff0c;AI图像生成技术已成为创意产业和科研领域的热点。Stable Diffusion作为其中的佼佼者&#xff0c;其性能和应用广受关注。…...

不确定性+电动汽车!含高比例新能源和多类型电动汽车的配电网能量管理程序代码!

前言 能源供应的可持续性和清洁性是当今世界共同关注的议题&#xff0c;配电网与可再生能源发电相结合&#xff0c;通过多能互补和梯级利用&#xff0c;在不同时空取长补短&#xff0c;提高能源利用率&#xff0c;减少温室气体排放&#xff0c;是解决能源短缺和环境问题的有效…...

准确-K8s系列文章-修改containerd 默认数据目录

修改 Kubernetes 集群中 containerd 默认数据目录为 /data/containerd 前言 本文档适用于 Kubernetes 1.24 及以上版本的集群&#xff0c;介绍如何将 containerd 默认的数据目录从 /var/lib/containerd 修改为 /data/containerd。 步骤 1. 停止 containerd 服务&#xff08…...

深入探索Linux命令:`aulastlog`

深入探索Linux命令&#xff1a;aulastlog 在Linux系统中&#xff0c;安全管理一直是管理员和用户关注的焦点。aulastlog是一个非常有用的工具&#xff0c;用于显示用户最近登录的日志。它通过分析/var/log/lastlog文件来提供这些信息&#xff0c;这个文件记录了系统上所有用户…...

Debezium日常分享系列之:Debezium 2.6.2.Final发布

Debezium日常分享系列之&#xff1a;Debezium 2.6.2.Final发布 一、新功能和改进1.Oracle 数据库查询过滤超过 1000 个表 二、修复和稳定性改进1.PostgreSQL 偏移刷新竞争条件2.Avro 兼容性 一、新功能和改进 1.Oracle 数据库查询过滤超过 1000 个表 Debezium Oracle 连接器允…...

PHP质量工具系列之phpmd

PHPMD PHP Mess Detector 它是PHP Depend的一个衍生项目&#xff0c;用于测量的原始指标。 PHPMD所做的是&#xff0c;扫描项目中可能出现的问题如&#xff1a; 可能的bug次优码过于复杂的表达式未使用的参数、方法、属性 PHPMD是一个成熟的项目&#xff0c;它提供了一组不同的…...

【java】速度搭建一个springboot项目

使用软件&#xff1a;IDEA&#xff0c;mysql 使用框架&#xff1a;springboot mybatis-plus druid 坑点 使用IDEA搭建一个springboot项目的时候&#xff0c;需要考虑一下IDEA版本支持的JDK版本以及maven版本。否则再构建项目&#xff0c;引入pom的时候就会报错。 需要检查…...

SystemVerilog测试框架示例

这里是一个完整的SystemVerilog测试框架示例&#xff0c;包括随机化测试和详细注释。 顶层模块 (Top Module) module top;// 信号声明logic clk;logic rst_n;// 接口实例化dut_if dut_if_inst(.clk(clk), .rst_n(rst_n));// DUT实例化 (假设DUT模块名为dut)dut u_dut(.clk(du…...

每天一个数据分析题(三百五十六)-图表决策树

图表决策树中将图表分成四类&#xff0c;分别是&#xff1f; A. 比较类 B. 序列类 C. 构成类 D. 描述类 数据分析认证考试介绍&#xff1a;点击进入 题目来源于CDA模拟题库 点击此处获取答案...

Prism 入门06,发布订阅(入门完结)

本章节介绍使用 Prism 框架的消息聚合器 IEventAggregator ,实现如何进行消息发布,订阅,取消订阅的功能 继续使用上一章节使用的 Prism WPF 空模板项目 BlankApp1 1.首先,在使用 Prism 框架当中,进行事件消息的发布和订阅之前,需要定义发布事件的事件消息模型。如下所示:…...

2. pytorch环境安装

概述 ​ 本文提供基于Anaconda环境Windows11操作系统的Pytorch深度学习环境的配置。深度学习环境分为GPU和CPU两大部分。使用GPU进行环境配置&#xff0c;需要保证电脑配有独立显卡&#xff0c;并且显卡驱动安装正常&#xff0c;详情见前文。 1. 创建新的虚拟环境用来配置Pyt…...

力扣爆刷第148天之贪心算法五连刷(区间合并)

力扣爆刷第148天之贪心算法五连刷&#xff08;区间合并&#xff09; 文章目录 力扣爆刷第148天之贪心算法五连刷&#xff08;区间合并&#xff09;一、406. 根据身高重建队列二、452. 用最少数量的箭引爆气球三、435. 无重叠区间四、763. 划分字母区间五、56. 合并区间六、738.…...

JSON及Python操作JSON相关

JSON及Python操作JSON相关 Json简介及Python操作Json相关示例。 1. JSON概念及支持的数据类型 1.1 什么是 JSON&#xff1f; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写&#xff0c;同时也易于机器解…...

[ 网络通信基础 ]——网络的传输介质(双绞线,光纤,标准,线序)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;网络通信基础TCP/IP专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年6月8日14点23分 &#x1f004;️文章质量&#xff1a;94分 前言—— 在现代通信网络中&#xff0c;传输介质是数据传…...

Android 高德地图API(新版)

新版高德地图 前言正文一、创建应用① 获取PackageName② 获取调试版安全码SHA1③ 获取发布版安全码SHA1 二、配置项目① 导入SDK② 配置AndroidManifest.xml 三、获取当前定位信息① ViewBinding使用和导包② 隐私合规设置③ 权限请求④ 初始化定位⑤ 获取定位信息 四、显示地…...

LeetCode---二叉树

144/94/145. 二叉树的前、中、后序的递归遍历 以中序遍历为例&#xff0c;其余类似&#xff1a; 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 代码示例&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* Tr…...

从0开发一个Chrome插件:核心功能开发——弹出页面

前言 这是《从0开发一个Chrome插件》系列的第十一篇文章,本系列教你如何从0去开发一个Chrome插件,每篇文章都会好好打磨,写清楚我在开发过程遇到的问题,还有开发经验和技巧。 专栏: 从0开发一个Chrome插件:什么是Chrome插件?从0开发一个Chrome插件:开发Chrome插件的必…...

安陆网站建设/网站建设品牌公司

【SymPy】&#xff08;一&#xff09;SymPy简介 【SymPy】&#xff08;二&#xff09;使用SymPy需要避开的坑 【SymPy】&#xff08;三&#xff09;基本操作&#xff08;四&#xff09;打印 简化 文章目录简化1 simplify2 多项式/有理函数简化2.1 expand2.2 factor2.2.3 colle…...

珠海在线网站建设/seo公司培训课程

哈喽大家好&#xff0c;我是无知便是罪&#xff0c;专注于收集和分享互联网上不为人知的好东西&#xff01;文件传输想必大家经常会用到&#xff0c;但是使用场景不同选择也不同&#xff01;像平常的小文件通过某些社交软件即可在手机与电脑之间快速传输。不过它们限制了文件大…...

wordpress语言切换 seo/品牌广告视频

索引是帮助mysql获取数据的数据结构。最常见的索引是Btree索引和Hash索引。不同的引擎对于索引有不同的支持&#xff1a;Innodb和MyISAM默认的索引是Btree索引&#xff1b;而Mermory默认的索引是Hash索引。Hash索引所谓Hash索引&#xff0c;当我们要给某张表某列增加索引时&…...

mariadb php wordpress/网页设计和网站制作

目前几乎所有架构的CPU都会提供PCI接口&#xff0c;网上也有很多文章对Linux PCI驱动进行分析&#xff0c;在写这篇文章的过程中大量阅读了这些文章&#xff0c;很多只涉及驱动的一部分&#xff0c;不够完整&#xff0c;对驱动代码中一些特殊操作也语焉不详。要弄懂PCI驱动需要…...

去年做那个网站致富/班级优化大师功能介绍

Description 在PJOI2010夏令营快要结束的时候&#xff0c;很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家&#xff0c;以便大家回去后继续学习。组委会觉得这个主意不错&#xff01;可是组委会一时没有足够的空光盘&#xff0c;没法保证每个人都能拿到刻录上资料…...

新乡网站建设公司黄页/discuz论坛seo设置

[转载自博客](http://blog.csdn.net/huang_wei_cai/article/details/52515817) 前言&#xff1a; Android Studio中对一个自己库进行生成操作时将会同时生成.jar与.aar文件。如下是本人测试可行的方案&#xff0c;需要学习的可以参考。 分别存储位置&#xff1a; *.jar&#x…...