AVL 树是最早被发明的自平衡树,得名于它的发明者 G. M. Adelson-Velsky 和 Evgenii Landis,他们在 1962 年的论文《An algorithm for the organization of information》中公开了这一数据结构。AVL 树在添加或移除节点时会尝试保持自平衡。任意一个节点(不论深度)的左子树和右子树高度最多相差 1。添加或移除节点时,AVL 树会尽可能尝试转换为完全树。
/** * 左左情况: 向右单旋转 * 左侧子节点的高度大于右侧子节点的高度时,并且左侧子节点也是平衡或左侧较重的,为左左情况 * * a b * / \ / \ * b c -> rotationLL(a) -> d a * / \ / \ * d e e c * * @param root Node<T> 旋转前的root节点 * @returns pivot Node<T> 返回旋转后的root节点(也就是旋转前的pivot) */ private rotationLL(root: Node<T>): Node<T> { // 先把pivot拿出来 const pivot = root.left; // root 左侧指向 pivot 的右子 root.left = pivot.right; // pivot 右侧指向 root pivot.right = root; // 返回 pivot return pivot; }
/** * 右右情况: 向左单旋转 * 右侧子节点的高度大于左侧子节点的高度,并且右侧子节点也是平衡或右侧较重的,为右右情况 * a c * / \ / \ * b c -> rotationRR(a) -> a e * / \ / \ * d e b d * * @param root Node<T> 旋转前的root节点 * @returns pivot Node<T> 返回旋转后的root节点(也就是旋转前的pivot) */ private rotationRR(root: Node<T>): Node<T> { // 先把pivot拿出来 const pivot = root.right; // root 右侧指向 pivot 的左子 root.right = pivot.left; // pivot 左侧指向 root pivot.left = root; // 返回 pivot return pivot; }
/** * 左右情况: 先左转子节点后右转 * 左侧子节点的高度大于右侧子节点的高度,并且左侧子节点右侧较重 * * a a e * / \ / \ / \ * b c -> rotationRR(b) -> e c -> rotationLL(a) -> b a * / \ / \ / \ / \ * d e b g d f g c * / \ / \ * f g d f * * @param node Node<T> */ private rotationLR(node: Node<T>): Node<T> { // 先把节点左子左转 node.left = this.rotationRR(node.left); // 再把节点本身右转 returnthis.rotationLL(node); }
/** * 右左情况: 先右转子节点后左转 * 右侧子节点的高度大于左侧子节点的高度,并且右侧子节点左侧较重 * * a a d * / \ / \ / \ * b c -> rotationLL(c) -> b d -> rotationRR(a) -> a c * / \ / \ / \ / \ * d e f c b f g e * / \ / \ * f g g e * * @param node Node<T> */ private rotationRL(node: Node<T>): Node<T> { // 先把节点右子右转 node.right = this.rotationLL(node.right); // 再把节点本身左转 returnthis.rotationRR(node); }