1. 概述
1.1 定义
平衡二叉树,全称为平衡二叉搜索树
它是由苏联数学家Adelson-Velsky 和 Landis提出来的,因此平衡二叉树又叫AVL树
平衡二叉树的定义是一种递归定义,要求每个节点都具有以下特性:
可以是一棵空树
左子树和右子树高度之差的绝对值不超过1(左右子树的高度差可以为0、1和 -1)
左子树和右子树均为平衡二叉树
为什么平衡二叉树是二叉搜索树?
之前,在学习二叉搜索树时,增删该查的效率最坏为O ( n ) O(n)O(n)。此时,二叉树退化成一条链
若二叉搜索树尽可能的平衡,增删改查的时间复杂度将稳定在O ( l o g 2 N ) O(log_2N)O(log
2
N)
因此,我们希望二叉搜索树是平衡的二叉树,我想这也是平衡二叉树是基于二叉搜索树提出来的原因
1.2 平衡因子与最小不平衡子树
平衡因子
定义中,左子树和右子树高度之差被称作平衡因子:左子树高度 - 右子树高度
AVL树中,要求 a b s ( 平 衡 因 子 ) < = 1 abs(平衡因子) <= 1abs(平衡因子)<=1,即左右子树的高度差为0、1和 -1
以上数值分别表示:左子树与右子树等高、左子树比右子树高、左子树比右子树矮
最小不平衡子树
平衡二叉树,要求平衡因子 a b s ( 平 衡 因 子 ) < = 1 abs(平衡因子) <= 1abs(平衡因子)<=1
下图,新插入节点37,该树不再是平衡二叉树。因为,节点58的左右子树高度差为2
从新插入节点向上查找,第一个 a b s ( 平 衡 因 子 ) > 1 abs(平衡因子) > 1abs(平衡因子)>1的节点为根的子树,被称为最小不平衡子树
上图中,新插入节点向上查找,节点58左右子树高度差为2,以节点58为根节点的子树,就是最小不平衡子树
关于最小不平衡子树的说明
新插入节点,可能导致平衡二叉树出现多棵不平衡的子树
此时,我们只需要调整最小不平衡子树,就能让整棵树平衡
2. 平衡二叉树的左旋/右旋
本章中,红色表示最小不平衡子树的根节点,蓝色表示新插入的节点
2.1 右旋
上图中,节点58为根节点的子树抽取出来。
想要让其变成二叉平衡树,最简单的想法,将根节点58向左儿子47的右下方下压(降低左子树高度)
下压后,根节点58成为左儿子47的右子树,将与左儿子原本的右子树51冲突
巧妙之处: 将原本的右子树51改成根节点58的左子树,整棵树恢复平衡
上述操作就是平衡二叉树的右旋:将根节点绕左儿子顺时针下压
右旋的规则
根节点成为左子节点的右子树
左子节点原本的右子树成为根节点的左子树(一个右子树被占据,一个左子树空闲,刚好可以互补)
新插入节点37的插入位置:根节点58的左儿子的左子树上,这种情况称为LL
后续,我们还将接触RR、LR、RL三种情况
2.2 左旋
下图中,新插入节点18,使得以12为根节点的树成为不平衡二叉树,最小不平衡子树的根节点也是12
此时,左子树比右子树矮2
要想平衡该二叉树,最直观的想法:将根节点12向右儿子15的左下方下压(降低右子树高度)
问题来了,此时根节点12成为右儿子的左子树,原本的左子节点13如何处理?
巧妙之处: 将原本的左子节13点变成节点12的右子树,整棵树恢复平衡
上述操作就是平衡二叉树的左旋:将根节点绕右儿子逆时针下压
左旋的规则
根节点成为右儿子点的左子树
右儿子原本的左子树成为根节点的右子树(一个左子树被占据,一个右子树空闲,刚好互补)
新插入节点18的位置:根节点12的右儿子的右子树,这种情况称为RR
2.3 调整的四种情况
上面小节中,我们通过右旋和左旋,见识了平衡二叉树调整的两种情况,分别是LL和RR
四种情况的描述
LL:新插入节点为最小不平衡子树根节点的左儿子的左子树上 → \rightarrow→ 右旋使其恢复平衡
RR:新插入节点为最小不平衡子树根节点的右儿子的右子树上 → \rightarrow→ 左旋使其恢复平衡
LR:新插入节点为最小不平衡子树根节点的左儿子的右子树上 → \rightarrow→ 以左儿子为根节点进行左旋,再按原始的根节点右旋
RL:新插入节点为最小不平衡子树根节点的右儿子的左子树上 → \rightarrow→ 以右儿子为根节点进行右旋,再按原始的根节点左旋