AVL 树

264 阅读4分钟

背景

  • 现有 [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 型为例进行推导及演示
// 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万现金大奖」 ”