文章目录

  • 一:AVL树基本概念
  • 二:AVL树实现原理
    • (1)构建AVL树
    • (2)构建演示
    • (3)旋转方法
      • A:右单旋转调整(插入到较高左子树左侧)
      • B:左单旋转调整(插入到较高右子树右侧)
      • C:先左后右双旋转调整(插入到较高左子树右侧)
      • D:先右后左双旋转调整(插入到较高右子树左侧)
  • 三:AVL树相关代码

一:AVL树基本概念

二叉排序树有一个缺陷:树的高度会直接影响其查找效率,且树越高效率越差,效率最差时为一棵单分支树

平衡二叉树(Self-Balancing Binary Search Tree):它首先是一颗二叉排序树,其中每个节点的左右子树高度之差绝对值不超过1。将二叉树上结点左子树和右子树高度之差的绝对值称之为平衡因子BF(Balance Factor),因此,平衡因子BF的取值只可能是-1、0和1中的一种

  • -1:表示该结点左子树高度小于右子树高度
  • 0:表示该结点左子树高度等于右子树高度
  • 1:表示该结点左子树高度大于右子树高度

以下是一些例子

  • ①是AVL树
  • ②不是AVL树,因为AVL树前提必须首先是二叉排序树
  • ③不是AVL树,因为结点58左子树高度为2,而右子树为高度为0,BF>1
  • ④是AVL树

最小不平衡子树:距离插入点最近的,且平衡因子绝对值大于1的结点为根的子树

如下,当插入新节点37时,距离它最近的平衡因子绝对值超过1的结点是58,所以58开始以下的子树为最小不平衡子树

二:AVL树实现原理

(1)构建AVL树

AVL树构建思想:在构建二叉排序树的过程中,每当插入一个结点时,先检查该结点的插入是否导致了平衡性被破坏,若不是则继续插入;若是则找出最小不平衡子树,在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点的链接关系,也即平衡调整,进行相应的旋转,使之成为新的平衡子树

int arr[10]={3,2,1,4,5,6,7,10,9,8}

假设上面数组需要构建为AVL树,由于AVL树首先是BST树,所以会构建成下面这样

但是我们知道,BST树很忌讳其高度太高,所以如果能调整为下面这样那再合适不过了,因为下面的树依然是一棵BST树,但是其高度小了很多,查找效率自然也会得到提高


因此对于AVL树的研究重点就在于如何调整,也就是如何旋转

(2)构建演示

对于333和222,构建时没有任何问题


来到111并将其插入后,发现根节点333的平衡因子变为了2,此时整棵树成为最小不平衡子树,需要进行调整:右单旋转调整(点击跳转查看)

  • 因为此时结点插入到了较高左树左侧

  • 调整后,222成为了根节点,333成为了222的右孩子,此树高度平衡

接着结点444到来,平衡因子没有变化

接着结点555到来,结点333的平衡因子变为-2,需要进行调整:左单旋转调整(点击跳转查看)

  • 因为此时结点插入到了较高右树右侧

  • 再次达到平衡

接着结点666到来,此时根节点222的平衡因子变为了-2,进行调整 左单旋转调整(点击跳转查看)

  • 因为此时结点插入到了较高右树右侧


结点777到来,结点5的平衡因子变为了-2,进行调整 左单旋转调整(点击跳转查看)

  • 因为此时结点插入到了较高右树右侧

结点101010到来,结构无变化

结点999到来,此时结点777的BF变为了-2,理应进行左单旋转调整,但是由于此时新结点插入到了较高右树左侧,故直接使用左单旋转调整是不可以的。(具体原因跳转过去会详细解释),需要进行 先右后左双旋转调整(点击跳转查看)

  • 很明显999插入了777的右子树左侧,故不能直接使用左单旋转

  • 故先对999和101010进行右旋,再对777、999和101010进行左旋

接着结点888插入,使结点666的BF变为了-2,属于插入到了较高右树的左侧,故需要进行 先右后左双旋转调整(点击跳转查看)

(3)旋转方法

大家最头疼的可能就是如何选择旋转方法了,总结如下,只需按照如下逻辑选择即可

A:右单旋转调整(插入到较高左子树左侧)

下图中为抽象树,三角形表示的树为高度平衡的二叉树排序树。如下情况中,结点A的平衡因子绝对值为1,左子树较高

此时来了一个新的结点恰好插入到了B结点的左树,导致A结点的平衡因子变为2,树不平衡,需要进行调整

调整时:将结点A下移一个高度,B上移一个高度,然后把B的右子树挂在A的左子树处(这样做可以保证二叉排序树的特性)

B:左单旋转调整(插入到较高右子树右侧)

左单调整和右单调整情况恰好相反,调整时结点B上移,结点A下移,让结点B的左子树做结点A的右子树

C:先左后右双旋转调整(插入到较高左子树右侧)

在右单旋转调整中,由于新的结点插入到了较高左子树的左侧,所以调整后可以使树平衡

但如果此时将新结点插入到较高左子树的右侧

此时如果继续使用右单旋转调整,你会发现怎么也调整不过去,依然不平衡

在这种情况下就要使用到双旋转调整了

我们先把较高左子树的右子树拆分一下,拆分为两棵树

大家会发现此时如果要在B的右侧插入一个结点有两个选择——要么插入到C的左侧,要么插入到C的右侧
这里我以插入到C的右侧为例

接着进行双旋转调整:先对B树进行左单旋转

形成了这样一颗树

然后对这颗树再进行右单旋转调整,树就平衡了

  • 本例是插入到了C的右侧,如果插入到了C的左侧,调整也是一样的

D:先右后左双旋转调整(插入到较高右子树左侧)

  • 特别注意:先看C部分再看本部分,C部分中解释较为详细,本部分只是逻辑相反

在左单旋转调整中,面对的情况是新节点插入到了较高右子树的右侧,而如果新节点插入到了较高右子树的左侧,那么就要使用先右后左双旋转调整

所以在这种情况下,先对右子树进行右单旋转调整,然后再进行左单旋转调整

三:AVL树相关代码

对于AVL树考研数据结构基本不涉及代码,其旋转过程逻辑并不难,只是需要多捋一捋。其代码实现有很多值得注意的地方,且稍不留心就容易掉坑,有兴趣的同学可以查看我的另一篇文章,其中代码都是可以跑通的,用C++实现

点击跳转

(王道408考研数据结构)第五章树-第四节2:平衡二叉树(AVL)及其旋转相关推荐

  1. (王道408考研数据结构)第五章树-第四节3:哈夫曼树基本概念、构造和哈夫曼编码

    文章目录 一:哈夫曼树基本概念 (1)相关术语 (2)哈夫曼树定义 二:哈夫曼树的构造 三:哈夫曼树特点 四:哈夫曼树典型应用-哈夫曼编码 在计算机中, 文件压缩是一项非常重要的技术,它除了可以减少文 ...

  2. (王道408考研数据结构)第五章树-第四节1:二叉树排序树(BST)及其操作

    文章目录 一:二叉排序树基本概念 二:二叉排序树查找 二:二叉排序树插入/构建 四:二叉排序树删除 (1)如果左子树为空 (2)如果右子树为空 (3)如果左右子树都不为空树 代码 测试 一:二叉排序树 ...

  3. (王道408考研数据结构)第五章树-第四节4:红黑树基本概念及操作

    文章目录 一:红黑树基本概念 (1)什么是红黑树 (2)红黑树的性质 (3)为什么要给空结点(NIL)上色? (4)为什么最长路径一定不超过最短路径的2倍? (5)红黑树效率 二:红黑树的实现 (1) ...

  4. (王道408考研数据结构)第五章树-第三节1:二叉树遍历(先序、中序和后序)

    文章目录 一:二叉树遍历概述 二:二叉树深度优先遍历 (1)先序遍历-根左右(NLR) (2)中序遍历-左根右(LNR) (3)后序遍历-左右根(LRN) 总结:三种遍历方式动图演示 三:二叉树的层序 ...

  5. (王道408考研数据结构)第五章树-第三节4:树与二叉树的转换

    文章目录 一:树.二叉树和森林的转换 (1)树转化为二叉树 (2)森林转化为二叉树 (3)二叉树转化为树 (4)二叉树转化为森林 二:树与森林的遍历 (1)树的遍历 (2)森林的遍历 一:树.二叉树和 ...

  6. (王道408考研数据结构)第五章树-第三节2:二叉树构造和重建

    文章目录 一:根据遍历序列构造二叉树 (1)由前序遍历和中序遍历构造二叉树 (2)由后序遍历和中序遍历构造二叉树 (3)由层次遍历和中序遍历构造二叉树 二:重建二叉树 一:根据遍历序列构造二叉树 (1 ...

  7. (王道408考研数据结构)第五章树-第一节:树的定义、基本用语和常考性质

    文章目录 一:树基本概念 (1)树的定义 (2)结点分类 (3)结点关系(相关术语) 二:树的常考性质 一:树基本概念 (1)树的定义 树(Tree):这是一种非线性结构.是 n n n(

  8. (王道408考研数据结构)第五章树-第三节3:线索二叉树

    相较于链表,二叉树的递归结构为其操作带来了一定的便利.如下二叉树的中序遍历结果为 D − G − B − E − A − F − C D-G-B-E-A-F-C D−

  9. (王道408考研数据结构)第六章图-第四节2:最小生成树之克鲁斯卡尔算法(思想、代码、演示、答题规范)

    文章目录 一:克鲁斯卡尔(Kruskal)算法思想 二:克鲁斯卡尔(Kruskal)算法代码实现 三:克鲁斯卡尔(Kruskal)算法视频演示 四:克鲁斯卡尔(Kruskal)算法动画演示 五:克鲁斯 ...

最新文章

  1. 使用计算机视觉算法检测钢板中的焊接缺陷
  2. rsync源目录写法的一点小细节
  3. python pyppeteer自定义chromium目录
  4. sql 2008 R2添加对MySql的远程服务器链接
  5. vxe-table安装和使用
  6. 存储过程 not supported yet_让我们来看看+Redis如何存储和计算一亿用户的活跃度
  7. 啊啊忍不住了,更!新!!!
  8. mysql 非等值条件 索引_慢SQL简述与定位
  9. Huffman树压缩和解压文件
  10. SubclassDlgItem函数
  11. 用python解决约瑟夫环
  12. 图形大小_光伏电池正面图形设计优化
  13. 听一下牛人是怎样自学MIT计算机系全部课程的[转]
  14. JSP 页面 嵌入 google API 地图
  15. 第 7 章 Neutron - 078 - 实践 Neutron 前的两个准备工作
  16. java开发利用jacob将word转pdf
  17. http中get和post详解
  18. C++(21)——反向输出一个三位数
  19. bp神经网络的训练过程,一文搞定bp神经网络
  20. 基于jsp+mysql+Spring+SpringMVC+mybatis的大学生缴费系统-计算机毕业设计

热门文章

  1. cgi mysql数据库_Perl CGI中操作Mysql数据库
  2. python怎么打开文件解释_python怎么打开文件的路径?
  3. adjacent angle_GRE/GMAT 数学之平面几何
  4. final关键字_Java面试-谈谈对final关键字的理解
  5. pandas学习笔记四之读取写入文件
  6. fcpx视觉特效插件包 - FxFactory for Mac 支持M1芯片
  7. matlab中函数的公式计算,MATLAB怎样定义函数(入门) 有一函数 f(x,y)=x^2+sinxy+2y , 写一程序, 输入自变量的值,输出函数值....
  8. NOI数学:狄利克雷(Dirichlet)卷积
  9. Intellij IDEA的java环境与安卓sdk配置实例教程
  10. Mysql数据库常用命令,mysql速学实用教程。