背景
- 现有
[5, 9, 8, 3, 2, 4, 1, 7]、[1, 2, 3, 4, 5]两个序列,依次插入二叉排序树中,结果如下:
- 二叉排序树本质上为了提高元素的检索效率而诞生的,但上面第二个序列对应的二叉排序树,却退化成了链表,那么检索效率也就退化成了
O(n) - AVL 树的出现就是为了解决二叉排序树的退化问题,相比于普通二叉排序树,它增加了平衡条件
AVL 树的基本信息
- 发明者:G.M. Adelson-Velsky 与 E.M. Landis
- 年代:1962
- 性质:
| H(left) - H(right) | <= 1,左右子树高度差不超过 1 - 优点:由于对每个节点的左右子树的树高之差做了限制,所以整棵树不会退化成链表
AVL 树的左旋与右旋
-
上图左树以 K1 为目标节点进行左旋,有点类似逆时针旋转
- K3 成为成为 K1 的父节点
- K3 的左子树 A 成为 K1 的右子树
-
上图右树以 K3 为目标节点进行右旋,有点类似顺时针旋转
- K1 成为 K3 的父节点
- K1 的右子树 A 成为 K2 的左子树
-
左旋右旋互为相反操作,且天然保持着二叉排序树的性质
-
AVL 树的失衡类型:
- LL 型 与 RR 型,是一对相似的失衡类型
- LL 型是指 K1 的左子树的左子树更高
- RR 型是指 K1 的右子树的右子树更高
- LL 型 与 RR 型,是一对相似的失衡类型
-
为了保持上面两种类型的树的平衡
- LL 型需要对根结点进行右旋操作
- RR 型则相反,需要对根节点进行左旋操作
- 下面以 LL 型为例进行推导及演示
// LL 型右旋平衡的推导过程
// 右旋前
h(k2) = h(a) + 1
h(k3) = max(h(c), h(d)) + 1
h(k2) = h(k3) + 2 // 关键
h(a) + 1 = max(h(c), h(d)) + 1 + 2
h(a) = max(h(c), h(d)) + 2
h(a) = h(b) + 1
// 右旋后
k1 左右子树高分别为 h(b) 与 h(k3) = max(h(c), h(d)) + 1
根据上面推导的公式,K1 的左右子树是平衡的
k2 左右子树高分别为 h(a) 与 h(b) + 1
根据上面推导的公式,K2 的左右子树是平衡的
而 K3 本来就是平衡的
所以进行右旋操作后的树是平衡的
- LR 型与 RL型,是一对相似的失衡类型
- LR 型指的是 K1 的左子树的右子树更高
- RL 型指的是 K1 的右子树的左子树更高
- 为了保持上面两种类型的树的平衡 - LR 型需要先将左子树根节点左旋操作,再将整棵树的根节点进行右旋操作 - RL 型则相反,需要先将右子树的根节点右旋操作,再将整棵树的根节点进行左旋操作
下面以 LR 型为例进行推导及演示
// LR 型调整平衡的推导过程
// 平衡操作前
h(k3) = max(h(c), h(d)) + 1
h(k3) = h(b) + 1 // 关键
h(b) = max(h(c), h(d))
h(k2) = h(k3) + 1 = h(b) + 2
h(k2) = h(a) + 2
h(b) = max(h(c), h(d)) = h(a)
// 平衡操作后
观察第三层的子树,由上面公式可知整棵树已经是平衡的了
- 在 AVL 树中依次插入上面两个序列中的元素
[5, 9, 8, 3, 2, 4, 1, 7]- 依次插入
5,9,8,从节点 5 处观察可知,树中第一次出现 RL 型失衡 - 从左至右,先将节点 5 的右子节点 9 进行右旋操作,再将节点 5 进行左旋操作,即可恢复树的平衡
- 继续插入
3,2,从节点 5 观察可知,树中出现 LL 型失衡 - 将节点 5 进行右旋操作,即可恢复树的平衡
- 继续插入
4,从节点 8 处可观察到树中出现 LR 型失衡 - 从左至右,先将节点 8 的左子节点 3 进行左旋操作,再将节点 8 进行右旋操作,即可恢复树的平衡
- 最后继续插入
1,7,平衡二叉排序树就完成了
[1, 2, 3, 4, 5]- 依次插入
1,2,3,从节点 1 处可观察到树中出现了 RR 型失衡,将节点 1 进行左旋操作,即可恢复树平衡
- 再次插入
4,5,从节点 3 处观察可知,树中出现了 RR 型失衡 - 将节点 3 进行左旋操作,即可恢复树平衡
代码演示
小结
- 本文介绍了 AVL 树的基本信息以及树中节点调整涉及到的左旋右旋操作
“ 本文正在参加「金石计划 . 瓜分6万现金大奖」 ”