看图轻松理解数据结构与算法系列(AVL树)

前言

推出一个新系列,《看图轻松理解数据结构和算法》,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握。本系列包括各类堆、各类队列、各类列表、各类树、各类图、各类排序等等几十篇的样子。mysql

AVL树

AVL树,也称平衡二叉搜索树,AVL是其发明者姓名简写。AVL树属于树的一种,并且它也是一棵二叉搜索树,不一样的是他经过必定机制能保证二叉搜索树的平衡,平衡的二叉搜索树的查询效率更高。算法

AVL树特色

  • AVL树是一棵二叉搜索树。
  • AVL树的左右子节点也是AVL树。
  • AVL树拥有二叉搜索树的全部基本特色。
  • 每一个节点的左右子节点的高度之差的绝对值最多为1,即平衡因子为范围为[-1,1]。

image

图中红色数字表示对应节点的高度,能够看到同一层的节点高度差都没有超过1。sql

二叉搜索树的平衡

基础的二叉搜索树构建出来可能会存在不平衡的现象,好比极端状况下,按照A B C D E F G H顺序插入树中,结果为,网络

image

但实际上咱们更想要平衡一点的二叉搜索树,由于平衡的二叉搜索树能有效提升查询效率,好比上面的要查询“H”节点则须要比较8个节点才找到,而平衡的二叉搜索树只须要比较3个节点。数据结构

因此AVL树的出现就是为了解决平衡性问题,它的核心内容就是平衡处理机制,即所谓的旋转,一共有四种形式的旋转:右单旋、左单旋、左右双旋和右左双旋。并发

为何要旋转

不论是什么方式的旋转,旋转的目的是为了下降树的高度,使其平衡,假如树结构以下图,机器学习

image

将“A”节点添加到树中,变成以下结构,树产生了不平衡,因而检查哪里不平衡,当到“C”节点时发现高度差超过1,数据结构和算法

image

因此须要对“C”节点进行右单旋操做将高度降到2,达到平衡。学习

image

插入方式

AVL树一共有四种插入方式,根据插入方式不一样须要作不一样的旋转操做,如今往下看四种插入方式,设受插入节点影响而失去平衡的节点的父节点为Z,.net

  • LL插入方式,插入的节点在Z节点的左子树的左子树上,以下图,“A”节点插入影响“C”节点的平衡,“C”的父节点为“E”,插入节点“A”在“E”节点的左子树的左子树上。即“B”节点的左右子节点都算LL插入。

image

  • RR插入方式,插入的节点在Z节点的右子树的右子树上,以下图,“I”节点插入影响“G”节点的平衡,“G”的父节点为“E”,插入节点“I”在“E”节点的右子树的右子树上。即“H”节点的左右子节点都算RR插入。

image

  • LR插入方式,插入的节点在Z节点的左子树的右子树上,以下图,“C”节点插入影响“B”节点的平衡,“B”的父节点为“E”,插入节点“C”在“E”节点的左子树的右子树上。即“D”节点的左右子节点都算LR插入。

image

  • RL插入方式,插入的节点在Z节点的右子树的左子树上,以下图,“G”节点插入影响“H”节点的平衡,“H”的父节点为“E”,插入节点“G”在“E”节点的右子树的左子树上。即“F”节点的左右子节点都算RL插入。

image

右单旋

右单旋用于处理LL插入方式,假设存在一棵树,以下,

image

现插入“A”节点,假如不进行旋转的话,树结构为下图,因此遍历过程也会检查哪里不平衡,检查到“C”节点和“G”节点的高度差大于1,并且插入节点“A”属于“E”节点左子树的左子树,因而进行右单旋,

image

“C”节点右单旋即将“C”节点提升,本来它的父节点“E”则变为其右子节点,“C”节点原来的右子节点则变为其父节点“E”的左子节点。右单旋后的结果以下,从新达到了平衡。

image

左单旋

左单旋用于处理RR插入方式,假设存在一棵树,以下,

image

现插入“I”节点,假如不进行旋转的话,树结构为下图,因此遍历过程也会检查哪里不平衡,检查到“C”节点和“G”节点的高度差大于1,并且插入节点“I”属于“E”节点的右子树的右子树,因而进行左单旋,

image

“G”节点左单旋即将“G”节点提升,本来它的父节点“E”则变为其左子节点,“G”节点原来的左子节点则变为其父节点“E”的右子节点。左单旋后的结果以下,从新达到了平衡。

image

左右双旋

左右双旋用于处理LR插入方式,假设存在一棵树,以下,

image

现插入“C”节点,假如不进行旋转的话,树结构为下图,遍历过程会检查哪里不平衡,检查到“B”节点和“G”节点的高度差大于1,并且插入节点“C”属于“E”节点的左子树的右子树,因而进行左右双旋,

image

先以“D”节点为轴进行左单旋,结果为,

image

再以“D”节点为轴进行右单旋,获得最终结果,

image

右左双旋

右左双旋用于处理RL插入方式,假设存在一棵树,以下,

image

现插入“G”节点,假如不进行旋转的话,树结构为下图,遍历过程会检查哪里不平衡,检查到“C”节点和“H”节点的高度差大于1,并且插入节点“G”属于“E”节点的右子树的左子树,因而进行右左双旋,

image

先以“F”节点为轴进行右单旋,结果为,

image

再以“F”节点为轴进行左单旋,获得最终结果,

image

插入

空树时插入节点“E”直接做为根节点,“E”节点高度设为1,

image

继续插入“B”节点,小于“E”节点则添加到左边,且“E”节点高度加1,

image

继续插入“G”节点,大于“E”节点则添加到右边,此时“E”节点高度不变,

image

继续插入“D”节点,最终到“B”节点的右子节点,此时“B”节点高度加1,“E”节点高度也加1,

image

继续插入“C”节点,最终到“D”节点的左子节点,此时“D”、“B”、“E”节点高度都分别加1,而且先发现节点“D”与它同级节点(不存在即高度为0)高度差大于1,而且属于RL插入方式,使用右左双旋处理,

image

以“C”节点为轴进行右单旋,结果为,

image

再以“C”节点为轴进行左单旋,结果以下,能够看到进过右左双旋操做后二叉树已经达到平衡了。

image

总结,插入时可能会遇到四种不一样的插入方式,分别是:LL插入方式、RR插入方式、LR和RL插入方式。根据不一样的插入方式对应作旋转操做即能使树达到平衡状态。

查找

AVL树由于属于二叉搜索树,因此查找时与BST树彻底同样,好比下面这棵树,查找“D”节点,

image

从根节点“C”开始,

image

“D”大于“C”,因此往右继续查找,

image

“D”小于“E”,因此往左查找,找到。

image

删除

删除操做主要分两种状况,一种是删除后不会影响平衡,那么直接按照BST树规则删除。另一种是删除后会影响树的平衡,那么则须要再作旋转处理。

状况一

如树的结构,要删除“B”节点,

image

直接找到“B”节点,且由于是叶子节点,直接删掉便可。

image

最终为,

image

但若是删除的不是“B”节点,而是“C”节点,则不能直接删除“C”节点,

image

应该先找到“C”节点的前驱,它的前驱为“B”节点,使用“B”替换“C”节点,

image

最后将原来的“B”节点删除。

image

状况二

如树的结构,要删除“F”节点,

image

先找到“F”节点,

image

而后将“F”节点删除,此时致使了“C”节点和“G”节点的高度差超过1,须要作旋转操做,

image

并且由于C节点的左子节点高度比右子节点高度大,因此执行右单旋操做,旋转后为,

image

-------------推荐阅读------------

个人开源项目汇总(机器&深度学习、NLP、网络IO、AIML、mysql协议、chatbot)

为何写《Tomcat内核设计剖析》

个人2017文章汇总——机器学习篇

个人2017文章汇总——Java及中间件

个人2017文章汇总——深度学习篇

个人2017文章汇总——JDK源码篇

个人2017文章汇总——天然语言处理篇

个人2017文章汇总——Java并发篇


跟我交流,向我提问:

欢迎关注:

相关文章
相关标签/搜索