数表查找之平衡二叉树
作者:互联网
文章目录
1.基本概念
平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:
它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
1.1.AVL引进
为什么会出现AVL这种树型结构?
如上图所示,序列是一个升序树,那么当出现这种情况的时候,二叉查找树就会退化为链表,这样搜索的效率又降低了。为了解决这个问题,引进了AVL树。因为这种数据结构很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。
而**对于二叉搜索树的查找效率取决于树的高度,因此保持树的高度最小,即可保证树的查找效率。**同样的序列 ,将其改为下图的方式存储,查找元素 6 时只需比较 3 次,查找效率提升一倍。
可以看出当节点数目一定,保持树的左右两端保持平衡,树的查找效率最高。
这种左右子树的高度相差不超过 1 的树为平衡二叉树。
1.2.AVL定义
平衡二叉查找树:简称平衡二叉树。由前苏联的数学家 Adelse-Velskil 和 Landis 在 1962 年提出的高度平衡的二叉树,根据科学家的英文名也称为 AVL 树。它具有如下几个性质:
- 可以是空树
- 假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过 1
平衡之意,如天平,即两边的分量大约相同。
1.3.AVL举例
上图肯定不是AVL树,因为节点60和节点66就不满足AVL树的定义。需要注意的是如果节点60不满足AVL树的定义,那么节点66也肯定就不满足AVL树的定义。
这个也不是AVL树,,节点66不满足AVL的定义。
这个就是AVL树了。
判断一棵树是不是AVL树其实有trick,你直接层序扫描以下就可以了,只要所有左右节点深度之差不大于1,那么就是AVL树了!
2.平衡因子
某节点的左子树与右子树的高度(深度)差即为该节点的平衡因子(BF,Balance Factor),平衡二叉树中不存在平衡因子大于 1 的节点。
在一棵平衡二叉树中,节点的平衡因子只能取 0 、1 、-1
,分别对应着左右子树等高,左子树比较高,右子树比较高。
3.AVL树插入时失衡与调整
现在的假设是提供一个AVL树
然后在上图的基础上插入一个节点元素,我们来看下动图:
最小失衡子树:在新插入的结点向上查找,以第一个平衡因子的绝对值超过 1 的结点为根的子树称为最小不平衡子树。也就是说,一棵失衡的树,是有可能有多棵子树同时失衡的。而这个时候,我们只要调整最小的不平衡子树,就能够将不平衡的树调整为平衡的树。
平衡二叉树的失衡调整主要是通过旋转最小失衡子树来实现的。根据旋转的方向有两种处理方式,左旋 与 右旋 。
旋转的目的就是减少高度,通过降低整棵树的高度来平衡。
3.1.左旋
加入新节点 99 后,节点 66 的左子树高度为 1,右子树高度为 3,此时平衡因子为 -2。为保证树的平衡,此时需要对节点 66 做出旋转,因为右子树高度高于左子树,对节点进行左旋操作,流程如下:
- 节点的右孩子替代此节点位置
- 右孩子的左子树变为该节点的右子树
- 节点本身变为右孩子的左子树
整个操作流程如下动图所示。
- 节点的右孩子替代此节点位置 —— 节点 66 的右孩子是节点 77 ,将节点 77 代替节点 66 的位置
- 右孩子的左子树变为该节点的右子树 —— 节点 77 的左子树为节点 75,将节点 75 挪到节点 66 的右子树位置
- 节点本身变为右孩子的左子树 —— 节点 66 变为了节点 77 的左子树
3.2.右旋
- 节点的左孩子代表此节点
- 节点的左孩子的右子树变为节点的左子树
- 将此节点作为左孩子节点的右子树。
注意:左旋和右旋是平衡二叉树基本且重要的操作,这个是后面四种插入的基础
4.AVL四种调整方式
大家可以想象以下,如果一颗AVL树由于新插入一个元素导致为一颗不平衡树,情况无非就是四种:
- 左节点的左子树
- 左节点的右子树
- 右节点的左子树
- 右节点的右子树
4.1.LL型调整
LL型调整比较简单,直接右旋即可。目的是将最小失衡子树旋转为数的根结点!
4.2.LR型调整
由于插入元素F插入的位置是E的左子树导致A节点失衡,而E节点是A的左节点的右子树。
而我们的目的是使得原来根节点的左孩子的右孩子 E 节点成为了新的根节点。
-
对节点B进行左旋操作
-
对节点A进行右旋操作
4.3.RL型调整
由于插入元素F插入的位置是A的右节点的左子树导致A节点失衡,而D节点是A的右节点的左子树。 而我们的目的是使得原来根节点的右孩子的左孩子 D 节点成为了新的根节点。
- 对节点C进行右旋操作
注意上面这副图中有问题,F因该为C的左节点而不是D的左节点!
- 对节点A进行左旋
注意上面这副图中有问题,F因该为C的左节点而不是D的左节点!
4.4.RR型调整
RR型调整比较简单,直接左旋即可。目的是将最小失衡子树旋转为数的根结点!
5.调整总结
对于插入导致AVL数不平衡的调整算法,记忆起来也是十分方便!
对于LL,RR型调整,我们的目的是将最小平衡树转为根节点,因此RR就是左旋,LL就是右旋。
对于LR,RL型调整,我们的目的是将插入节点的父节点转为根节点,RL就是先右旋再左旋,LR就是先左旋在右旋。
6.删除节点
AVL树和二叉查找树的删除操作情况一致,像网上有人还把待删除的节点分为什么叶子节点等等,其实这个你在设计算法的时候考虑进去就可以了,特别是根节点的那种情况贼坑,我记得我是用二维指针实现的!
(1条消息) 数表查找之二叉搜索树_非常规自我实现的博客-CSDN博客
删除节点是树中比较难的一个地方,上面是我写的删除节点的算法,非常的巧妙,如果看不懂可以和我交流!
总结
7.参考博客
(1条消息) 平衡二叉树_月雲之霄的博客-CSDN博客_平衡二叉树
这篇博客有AVL数据结构的实现,我就不实现了,原因在于我觉得我已经把二叉搜索树实现了,AVL在它的基础上增加了一些限制而已,并且后面又很多变种树形结构,因此我觉得知道基础实现就可以了,后面的那些知道概念就好
标签:左子,右子,AVL,平衡,查找,二叉树,数表,节点 来源: https://blog.csdn.net/qq_46359697/article/details/122214020