数据结构-AVL

简介

普通的二分搜索树是有可能退化成链表的,这意味着时间复杂度从 O ( l o g 2 n ) O(log_2{n}) O(log2n)降至 O ( n ) O(n) O(n),为了规避这种现象,平衡二叉树的概念应运而生。

在计算机科学中,AVL树是最先发明的自平衡二叉查找树。AVL树得名于它的发明者G. M. Adelson-VelskyE. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。

特点

  1. 本身首先是一棵二叉搜索树。

  2. 带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。

相关概念

平衡因子

左右子树高度差。只要高度差不超过1,则为平衡状态。否则就得想办法使其平衡。这个方法叫旋转👇

旋转

增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

右旋

图片来源

左旋

与右旋相反

组合

左旋右旋是调整平衡的最小操作,这意味着在更复杂的情况下需要进行左旋右旋组合操作才能达到目的,什么情况下适合什么样的操作呢?

  • LL:由于在当前节点左子树的左子树上插入节点,导致平衡因子由1增至2,此时只需进行一次右旋操作

  • RR:与LL相反

  • LR:在左子树的右子树上插入节点导致失衡,需要先左旋后右旋

  • RL:与LR相反

实现

完整代码

节点

维护平衡的前提是通过旋转,而旋转的本体是节点,因此将其放在节点类中。

  1. 平衡因子

            private int getBalanceFactor() {
                return getHeight(left) - getHeight(right);
            }
            private static int getHeight(Node node) {
                return node == null ? 0 : node.height;
            }
    
  2. 旋转(以右旋为例),同时刷新高度

    刷新高度操作不需要担心空指针问题,交给调用者👇

            public Node<K, V> rightRotate() {
                Node x = this.left;
                Node t = x.right;
                x.right = this;
                this.left = t;
                return x.refreshHight();
            }
            private Node<K, V> refreshHight() {
                height = 1 + Math.max(getHeight(this.left), getHeight(this.right));
                return this;
            }
    
  3. 平衡

            public Node<K, V> balance() {
                int balanceFactor = getBalanceFactor();
                if (balanceFactor > 1 && left.getBalanceFactor() >= 0) {
                    return rightRotate();
                }
                if (balanceFactor < -1 && right.getBalanceFactor() <= 0) {
                    return leftRotate();
                }
                if (balanceFactor > 1 && left.getBalanceFactor() < 0) {
                    left = left.leftRotate();
                    return rightRotate();
                }
                if (balanceFactor < -1 && right.getBalanceFactor() > 0) {
                    right = right.rightRotate();
                    return leftRotate();
                }
                return this;
            }
    

AVL

在二分搜索树的基础上增加平衡操作

    private Node<K, V> balance(Node<K, V> node) {
        return node == null ? null : node.balance();
    }

在增删等可能影响平衡的方法中调用平衡:

    public Node<K, V> add(Node<K, V> node, K k, V v) {
        if (node == null) {
            size++;
            return new Node<>(k, v);
        }
        Comparator<K> kComparator = Comparator.naturalOrder();
        if (Objects.compare(k, node.key, kComparator) < 0) {
            node.left = add(node.left, k, v);
        } else if (Objects.compare(k, node.key, kComparator) > 0) {
            node.right = add(node.right, k, v);
        } else {
            node.value = v;
        }
        return node.balance();
    }
    public Node<K, V> remove(Node<K, V> node, K k) {
        if (node == null) {
            return null;
        }
        if (k.compareTo(node.key) < 0) {
            node.left = remove(node.left, k);
            return node.balance();
        } else if (k.compareTo(node.key) > 0) {
            node.right = remove(node.right, k);
            return node.balance();
        }
        size--;
        if (node.left == null) {
            Node<K, V> right = node.right;
            node.right = null;
            return balance(right);
        }
        if (node.right == null) {
            Node<K, V> left = node.left;
            node.left = null;
            return balance(left);
        }
        Node<K, V> successor = minimum(node.right);
        successor.right = remove(node.right, successor.key);
        size++;
        successor.left = node.left;
        node.left = node.right = null;
        return balance(successor);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值