AVL树又称平衡二叉搜索树,它能保证二叉树高度相对平衡,尽量降低二叉树的高度,提高搜索效率。
它具有以下特点:
1. 左子树和右子树的高度之差的绝对值不超过1
2. 树中的每个左子树和右子树都是AVL树
3. 每个节点都有一个平衡因子(balance factor--bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子 4. 树的高度 ) .
AVL树出了会自平衡就是一个普通的二叉树,所以我们主要研究它的平衡策略。
平衡策略
AVL树一旦不平衡,就可以通过一个简单的动作迭代使平衡——旋转。
我的理解是,一棵树就好像是一个天平,平衡就意味着两边的砝码差不多(在树中就是子树的高度)。如果一般砝码多,就用旋转让两边高度恢复平衡。从最早出现不平衡的那颗子树开始旋转,到平衡为止。
而旋转策略如下:
LL | 在a的左子树根节点的左子树上插入节点而破坏平衡 | 右旋转 |
RR | 在a的右子树根节点的右子树上插入节点而破坏平衡 | 左旋转 |
LR | 在a的左子树根节点的右子树上插入节点而破坏平衡 | 先左旋后右旋 |
RL | 在a的右子树根节点的左子树上插入节点而破坏平衡 | 先右旋后左旋 |
这么看起来比较抽象,我用实例来展示旋转过程,也许能帮助理解:
1. 如下图所示,该数增加了节点10以后:
a.20节点左子树高度为1, 右子树高度为0,子树平衡。
b.30节点的左子树高度为2,右子树高度为0,两边差值超过了1,不平衡。
c.根据左子树的左节点造成子树不平衡的策略(LL),我们应该右旋转整棵树。
旋转后左右子树平衡如下图:
2. 好,我们再来看看RR策略如何实现,现在我们向这棵树插入节点40:
3. 此时可以看出虽然有点歪,但是这棵树总体来说还是符合AVL树特点的,并不需要旋转。于是为了创造场景,我们继续插入节点50:
插入50以后我们来从50往上看:
a. 40节点,左子树高度为0,右子树高度为1,平衡,不需要调整。
b. 30节点,左子树高度为0,右子树高度为2,不平衡,需要调整。
那么我们就先调整30节点为根节点的子树,这课子树是右子树的右节点导致不平衡,那么根据RR策略,我们只需要对子树进行左旋转。
旋转完以后的结果如图:
这样40节点就已经平衡了,我们再看上面的20节点,左右子树高度平衡,不需要调整。
4. 我们如果继续向其中插入60节点呢:
a. 50节点,左子树高度为0,右子树高度为1,平衡。
b. 40节点,左子树高度为1,右子树高度为2,平衡。
c. 20节点,左子树高度为1,右子树高度为3,不平衡,因为60为20的右子树根节点的右节点,此时执行策略左旋转。
旋转以后,40变成了根节点,30变成了20的右子节点,如下:
树再次平衡。
5. 为了验证RL策略,继续插入55.
好,我们按照之前的分析方法,从新插入的55节点的父节点开始看。
a. 60节点,左子树高度为1,右子树为0,平衡。
b. 50节点,左子树高度为0,右子树高度为2,不平衡。
按照RL策略,我们应该先右旋,然后左旋。
右旋以后,如下图:
图中可见50节点还是不平衡的:
左旋以后如下图:
6. 我们继续插入节点5
此时检查一遍,所以树和子树都是平衡的。
7. 所以我们继续插入8.
重复一遍分析过程:
a. 节点5左子树为0, 右子树为1,平衡。
b. 节点10左子树为2,右子树为0,不平衡。
此时引起不平衡的节点为8,节点在以10为根节点的子树的左子树右节点,适用LR策略,先左旋,再右旋。
左旋以后图为:
此时10节点依然不平衡。
右旋以后,如图就又平衡了
四种旋转策略,已经演示完成,分析方法同上,就可以让不平衡的二叉树,回到平衡状态。