搜索树中,由于结点插入顺序不同,将导致不同的深度和不同的平均查找长度(ASL) 二叉搜索树一般ASL计算方法:(每层结点个数 * 层数)之和 / 结点个数
平衡因子(Balance Factor BF):
BF(T) = \(h_L\) - \(h_R\) (注:\(h_L\) 和 \(h_R\)分别为左右子树的高度)
平衡二叉树(Balance Binary Tree):AVL树 空树,或者任意结点左右子树高度差绝对值不超过1,即|BF(T)| <= 1
平衡二叉树是为了提升查找效率而提出的一种树的结构,其是基于二叉搜索树的,也就是满足二叉搜索树右大左小的道理。 所以给定节点数为n的AVL树,其最大高度为O(\(log_2n\))
AVL树的结构代码:
1 | /* AVL树的类型 */ |
平衡二叉树要保持平衡态是不容易的,插入一个元素之后,很可能就会破坏平衡,所以为了保证其一直处于平衡态,我们就需讨论在插入元素并破坏平衡态之后如何再次调整为平衡态,同时,还要保证其是二叉搜索树。
平衡二叉树的调整
相关说明: 破坏平衡的结点又可称之为 “麻烦节点” 被破坏平衡的结点又可称之为 “发现者”
RR旋转
也就是 “麻烦节点” 在 “发现者” 右子树的右边
调整方式: 将 “发现者” 右子树的根节点提上来代替 “发现者” 的位置,“发现者”连同其左子树作为新的左子树,而 “发现者” 右子树根节点原来的左子树作为 “发现者” 的右子树,右边不变,如图:
代码实现:
调整平衡如上解释,只采用三步即可完成:
- 将 “发现者” 右子树的根节点提上来代替 “发现者” 的位置,即将 “发现者” 右子树赋值给一个新结点
- “发现者” 右子树根节点原来的左子树作为 “发现者” 的右子树,即将“发现者” 右子树根节点原来的左子树赋值给 “发现者” 的右子树
- “发现者” 连同其左子树作为新的左子树,即将 “发现者” 赋值给新树树的左节点
1 | /* 右单旋 更新高度并返回新结点 B */ |
LL旋转
也就是 “麻烦节点” 在 “发现者” 左子树的左边
理论以及实现和RR旋转相同,只不过操作位置相反,省去解释
代码: 代码实现的前提:A必须要有一个左子节点B
1 | /* 左单旋 更新高度并返回新结点 B */ |
LR旋转
也就是 “麻烦结点” 在左子树的右边
对于LR旋转,我们可以将其分为两步: 1. 首先将 “发现者” 的左子树进行RR旋转
- 再将 “发现者” 本身进行LL旋转,返回即可
示意图如下:
** 代码:**
1 | /* 将B与C做右单旋,C被返回 */ |
RL旋转
也就是 “麻烦结点” 在右子树的左边
与LR旋转对称,RL仍然何以分为两步: 1. 首先将 “发现者” 的右子树进行LL旋转 2. 再将 “发现者” 本身进行RR旋转,返回即可
代码简略,直接省去
平衡二叉树的插入
解决了平衡二叉树的调整问题,我们便可以方便地讨论其插入问题
问题简单,直接上代码
代码:
1 | AVLTree Insert(AVLTree T, ElementType X){ |