Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

二叉平衡树(AVL)-构造解释

  • 概念

    • AVL树中任何节点的两个子树的高度最大差为1,因此非常平衡
  • 平衡的好处

    • 可以让查找、插入、删除在平均或最坏情况下都是O(logN)
  • 定义

    class AVLNode {
        constructor(key) {
            this.key = key;
            this.height = 0;
            this.left = null;
            this.right = null;
        }
    }
    
  • 四种情况

    • LL 左左

      • 添加元素到左子节点的左子节点上,导致二叉树失衡
      • 需要做一次顺时针单旋恢复平衡,针对根节点、左子节点、左子节点的右子节点
      function leftLeftRotation(root) {
          const left = root.left;
          root.left = left.right;
          left.right = root;
      
          root.height = Math.max(root.left.height, root.right.height) + 1;
          left.height = Math.max(root.height, left.left.height) + 1;
      
          return left;
      }
      
    • RR 右右

      • 添加元素到右子节点的右子节点上,导致二叉树失衡
      • 需要做一次逆时针单旋恢复平衡,针对根节点、右子节点、右子节点的左子节点
      function rightRightRotation(root) {
          const right = root.right;
          root.right = right.left;
          lright.left = root;
      
          root.height = Math.max(root.left.height, root.right.height) + 1;
          right.height = Math.max(root.height, right.right.height) + 1;
      
          return right;
      }
      
    • LR 左右

      • 添加元素到左子节点的右子节点上,导致二叉树失衡
      • 需要做两次旋转
        • 一次RR逆时针,其中RR的根节点就是原左子节点
        • 一次LL顺时针,其中LL的根节点就是原根节点
      function leftRightRotation(root) {
          root.left = rightRightRotation(root.left);
          return leftLeftRotation(root);
      }
      
    • RL 右左

      • 添加元素到右子节点的左子节点上,导致二叉树失衡
      • 需要做两次旋转
        • 一次LL顺时针,其中LL的根节点就是原右子节点
        • 一次RR逆时针,其中RR的根节点就是原根节点
      function rightLeftRotation(root) {
          root.right = leftLeftRotation(root.right);
          return rightRightRotation(root);
      }
      
  • 获取高度

    function height(root) {
        if (!root) return 0;
        return root.height;
    }
    
  • 获取最值节点

    function getMax(root) {
        if (root.right) {
            return getMax(root.right);
        } else {
            return root;
        }
    }
    
    function getMin(root) {
        if (root.left) {
            return getMin(root.left);
        } else {
            return root;
        }
    }
    
  • 插入

    function insertNode(root, key) {
        if (root == null) {
            root = new AVLNode(key);
        } else {
            if (key < root.key) {
                root.left = insertNode(root.left, key);
                if (root.left.height - root.right.height == 2) {
                    if (key < root.left.key) {
                        root = leftLeftRotation(root);
                    } else {
                        root = leftRightRotation(root);
                    }
                }
            } else if (key > root.key) {
                root.right = insertNode(root.right, key);
                if (root.right.height - root.left.height == 2) {
                    if (key < root.right.key) {
                        root = rightLeftRotation(root);
                    } else {
                        root = rightRightRotation(root);
                    }
                }
            } else {
                console.lgog("insert failed")
            }
        }
    
        root.height = Math.max(root.left.height, root.right.height) + 1;
    
        return root;
    }
    
  • 删除

    function removeNode(root, key) {
        if (root == null) return;
        if (!search(root, key)) return;
        
        if (key < root.key) {
            root.left = removeNode(root.left);
            if (height(root.right) - height(root.left) == 2) {
                if (height(root.right.left) > height(root.right.right)) {
                    root = rightLeftRotation(root)
                } else {
                    root = rightRightRotation(root);
                }
            }
        } else if (key > root.key) {
            root.right = removeNode(root.right);
            if (height(root.left) - height(root.right) == 2) {
                if(height(root.left.left) > height(root.left.right)) {
                    root = leftLeftRotation(root);
                } else {
                    root = leftRightRotation(root);
                }
            }
        } else {
            if (!root.left && !root.right) {
                root = null;
            } else if(!root.left) {
                root = root.left;
            } else if(!root.right) {
                root = root.right;
            } else {
                if (height(root.left) > height(root.right)) {
                    let max = getMax(root.left);
                    root.key = max.key;
                    root.left = removeNode(root.left, max);
                } else {
                    let min = getMin(root.right);
                    root.key = min.key;
                    root.right = removeNode(root.right, min);
                }
            }
        }
    
        return root;
    }