二叉搜索树(2)之AVL树 笔记

2020-07-08  本文已影响0人  甲乙飞鱼

AVL树的特点

  1. 每个节点的平衡因子只可能是 -1、 0、 1 (绝对值 < 1,如果大于一,则称之失衡)
  2. 每个节点的左右两端的高度差不超过1
  3. 添加 搜索 删除 的时间复杂度是O(log n)

添加

    protected void afterAdd(Node<E> node) {
        while ((node = node.parent) != null) {
            if (isBalanced(node)) {
                // 更新高度
                ((AVLNode<E>)node).updateHeight();
            } else {
                // 恢复平衡
                rebalance(node);
                // 整棵树恢复平衡
                break;
            }
        }
    }

更新节点高度

    public void updateHeight() {
        int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
        int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
        height = 1 + Math.max(leftHeight, rightHeight);
    }

恢复平衡

    /**
     * 恢复平衡
     * @param grand 高度最低的那个不平衡节点
     */
    private void rebalance(Node<E> grand) {
        //获取失衡节点的儿子节点(左右子节点比较高的那个)
        Node<E> parent = ((AVLNode<E>)grand).tallerChild();
        //获取失衡节点的孙子节点
        Node<E> node = ((AVLNode<E>)parent).tallerChild();
        if (parent.isLeftChild()) { // L
            if (node.isLeftChild()) { // LL
                rotateRight(grand);
            } else { // LR
                rotateLeft(parent);
                rotateRight(grand);
            }
        } else { // R
            if (node.isLeftChild()) { // RL
                rotateRight(parent);
                rotateLeft(grand);
            } else { // RR
                rotateLeft(grand);
            }
        }
    }
  1. parent节点在grand节点的left边 node节点在parent 的left边 只需要对 grand 进行 right旋转,即可恢复该失衡节点的平衡
  2. parent节点在grand节点的left边 node节点在parent 的rigth边 则需要先对parent进行left 旋转 grand进行right旋转,即可恢复该失衡节点的平衡
  3. parent节点在grand节点的right边 node节点在parent 的right边 只需要对 grand 进行 left旋转,即可恢复该失衡节点的平衡
  4. parent节点在grand节点的right边 node节点在parent 的left边 则需要先对parent进行right 旋转 grand进行left旋转,即可恢复该失衡节点的平衡

旋转

    protected void rotateLeft(Node<E> grand) {
        //对谁进行左旋转 谁就被认为是祖父节点
        //找到 parent 节点
        Node<E> parent = grand.right;
        //找到child 节点
        Node<E> child = parent.left;
        
        //左旋转时 
        // grang  下来  pareng.left = grand; 
        // grang.right = child
        grand.right = child;
        parent.left = grand;
        // 改变了 树中的 两条线 所以得维护三个节点的父节点属性 与 原来指向grang 改为指向 parent
        afterRotate(grand, parent, child);
    }
    protected void rotateRight(Node<E> grand) {
        Node<E> parent = grand.left;
        Node<E> child = parent.right;
        grand.left = child;
        parent.right = grand;
        afterRotate(grand, parent, child);
    }
    protected void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {
        // 让parent称为子树的根节点
        parent.parent = grand.parent;
        //原来指向garent的那条线 指向 parent
        if (grand.isLeftChild()) {
            grand.parent.left = parent;
        } else if (grand.isRightChild()) {
            grand.parent.right = parent;
        } else { // grand是root节点
            root = parent;
        }
        
        // 更新child的parent
        if (child != null) {
            child.parent = grand;
        }
        
        // 更新grand的parent
        grand.parent = parent;
    }

删除

    protected void afterRemove(Node<E> node) {
        while ((node = node.parent) != null) {
            if (isBalanced(node)) {
                // 更新高度
                updateHeight(node);
            } else {
                // 恢复平衡
                rebalance(node);
            }
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读