AVL树的介绍和实现

我们知道,二叉搜索树是会出现单向的。单向在查找时效率是非常低的,时间复杂度会退化成O(N),而AVL树就是解决这个问题
在这里插入图片描述

1. AVL 树

1.1 AVL树的概念

概念:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右
子树高度之差的绝对值不超过1(需要对树中的结点进行调整)。

性质:1. 它的左右子树都是AVL树。2. 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

1.2 AVL树节点的定义

在这里插入图片描述
AVL树并没有规定必须要设计平衡因子,只是一个实现的选择,方便控制平衡。

1.3 插入后的平衡因子

首先,我们还是按照之前插入的方式:
在这里插入图片描述

这里主要是插入的父结点要更新。
那么一个新结点插入树中后,它的平衡因子怎么变化(是右子树-左子树为例),我们来看:
在这里插入图片描述
我们在9的左边插入一个新结点,哪些平衡因子会发生变化呢?
在这里插入图片描述
我们可以看到,需要改变的是插入结点的祖先。其余结点不需要改变。
每个祖先的平衡因子如果改变成1或者-1,说明原来是0,子树的高度发生了变化,需要继续往上更新。
在这里插入图片描述
此时,父亲的平衡结点为0。说明parent为根的树高度不变,不需要在往上更新了。
在这里插入图片描述
这里parent的平衡因子变成了2,违反了AVL树的规则,就不需要再往上更新了,我们要旋转子树。

基本规则如下:
1.子树高度变了,就继续往上更新。
2.子树高度不变,就完成更新。
3.子树违反平衡规则,就旋转子树。

代码实现:
在这里插入图片描述

1.4 AVL树的旋转

根据节点插入位置的不同,AVL树的旋转分为四种:

1.4.1 右右:左单旋

1. 新节点插入较高右子树的右侧—右右:左单旋
在这里插入图片描述
左单旋是将60的左边放到30的右边,然后将30放到60的左边。

代码实现思路:
我们先将我们要修改的位置给标记上:
在这里插入图片描述
我们用parent,SubR,SubRL来标记我们要修改的结点。我们可以根据上图来分析,parent改到SubR的左边,SubRL改到parent的右边。
在这里插入图片描述
还有我们要把三叉链中的父指针更新:
在这里插入图片描述
这里我们还要注意:SubRL可能为空,所以我们需要加一个判断。
在这里插入图片描述
到这里了,还是没有结束。因为parent可能是根,也可能不是根。
在这里插入图片描述
这是parent不为根且SubRL为空的情况,旋转之后为:
在这里插入图片描述
我们需要将7和9(SubR)连起来。
在这里插入图片描述
左单旋的平衡因子:
在这里插入图片描述
从上图我们可以看出,只有parent和SubR的平衡因子发生了变化。SubRL的高度并没有发生改变。
在这里插入图片描述
从上图也可以看出,当parent的平衡因子为2,cur的平衡因子为1时。就会发生左单旋。
在这里插入图片描述

1.4.2 左左:右单旋

2. 新节点插入较高左子树的左侧—左左:右单旋
在这里插入图片描述
这里把30的右边转到60的左边,然后把60转到30的右边。

代码实现思路:
还是要将修改的位置给标记上:
在这里插入图片描述
我们将SubLR放到parent的左边,把parent放到SubL的右边。其余和上面的左单旋类似。

在这里插入图片描述
在这里插入图片描述

1.4.3 左右:先左单旋再右单旋

3. 新节点插入较高左子树的右侧—左右:先左单旋再右单旋

什么是较高左子树的右侧?
在这里插入图片描述
在这里插入图片描述
当然在b插入或者c插入都会引起这种情况。

那么我们该怎么旋转呢?
在这里插入图片描述
在这里插入图片描述
将双旋变成单旋后再旋转,即:先对30为根进行左单旋,然后再对90为根进行右单旋。

但是还有一种平衡因子变化,没有考虑到
因为h为0的时候,平衡因子不一样了。
在这里插入图片描述虽然有三种平衡因子的情况,但是旋转的方法都是一样的。

那么我们该怎么区分这三种情况呢
答案是:观察60这个结点的平衡因子

代码实现:
在这里插入图片描述
我们还是先给这三个位置标记上。
在这里插入图片描述
但是此时我们左旋转和右旋转后,树的平衡因子被打乱了。我们需要重新更新平衡因子。根据上图的三种情况来更新,会比较容易。
在这里插入图片描述
在这里插入图片描述

1.4.4 右左:先右单旋再左单旋

4. 新节点插入较高右子树的左侧—右左:先右单旋再左单旋。

那么这个情况和上一种类似,我们直接来看图:
在这里插入图片描述
将双旋变成单旋后再旋转,即:先对90为根进行右单旋,然后再对30为根进行左单旋。

代码实现:
在这里插入图片描述
在这里插入图片描述

1.5 AVL树的验证

在这里插入图片描述
在这里插入图片描述

1.6 AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值