【数据结构】 AVL树

AVL(G. M. Adelson-Velsky & E. M. Landis)树是最早的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。

  • 定义
  • 平衡
  • 实现

定义

定义:左子树的高度减右子树的高度的绝对值小于等于1

基于以上的定义,每当插入或删除节点时就有可能导致整棵树不平衡,这个时候我们就需要重新通过计算所谓的【平衡因子】,对树进行再平衡(rebalance)操作。

平衡因子:某个结点的左子树的高度减去右子树的高度得到的差值。

平衡

单旋转:只用旋转一次既可以达成平衡,根据情况分为左旋和右旋。

下图是相对简单的右旋,下图的结点的【1】的左树高度为2,右树高度为0,两端的高度差超过1,处于不平衡的状态,这个时候需要进行旋转使之处于平衡状态。下图相对简单,只要将【2】作为跟根将【1】作为2的右子树即可达成。


简单的右旋

下图是相对复杂的右旋,总共的层级是在4层左右,左子树的高度为3,右子树的高度为1。这个时候我们需要以【4】为跟,并将【6】作为【4】的右树。那么【4】原先的右树【5】需要作为【6】的左树。这样我们就完成了这个相对复杂的右旋。两种右旋,看起来不一样,实际原G理差不多。


复杂的右旋

下述左旋也类似上述的右旋。
简单的左旋
复杂的左旋

双旋转:需要旋转两次才能达成,首先需要对最高的【子树】进行左旋或者右旋,然后对当前的树进行旋转。

如下图所示,第一个树无法通过上述旋转一次达成平衡,先将【2】的子树【5】右旋,将【4】作为【2】的子树,之后达成第二颗树的效果,之后将【4】节点作为根节点,通过一个左旋达成第三颗树的平衡效果。也双旋转是通过子树的旋转后,再通过本身树的旋转达成平衡。


双旋转

实例

如下述代码所示,实质上的旋转方式就2中,一种是左旋、另一种是右旋。而双旋转,则是左旋和右旋的组合,先通过子树的旋转,再通过本身树的旋转进行的组合旋转。在下述的代码中,我们可以看到旋转的方式基本就4种。

  • 左旋
  • 右旋
  • 左子树左旋,本树右旋
  • 右子树右旋,本书左旋
    依照上述的类型,我们基本可以做到AVL树的平衡
    private AvlTreeNode rebalance(AvlTreeNode root) {

        root.left = null == root.left ? null : rebalance(root.left);
        root.right = null == root.right ? null : rebalance(root.right);
        if (root.getBalanceFactor() > 1) {
            if (root.left.getBalanceFactor() == 1) {
                // 右旋转
                return turnRight(root);
            } else if (root.left.getBalanceFactor() == -1) {
                root.left = turnLeft(root.left);
                return turnRight(root);
            }
        } else if (root.getBalanceFactor() < -1) {
            if (root.right.getBalanceFactor() == 1) {
                root.right = turnRight(root.right);
                return turnLeft(root);
            } else if (root.right.getBalanceFactor() == -1) {
                // 左旋转
                return turnLeft(root);
            }
        }
        return root;
    }
    private AvlTreeNode turnRight(AvlTreeNode root) {
        AvlTreeNode tmpRoot;
        tmpRoot = root.left;
        root.parent = root.left;
        root.left = root.left.right;
        tmpRoot.right = root;
        return tmpRoot;
    }

    private AvlTreeNode turnLeft(AvlTreeNode root) {
        AvlTreeNode tmpRoot;
        tmpRoot = root.right;
        root.parent = root.right;
        root.right = root.right.left;
        tmpRoot.left = root;
        return tmpRoot;
    }

// 树节点
    static class AvlTreeNode {

        public AvlTreeNode(T element) {
            this.element = element;
        }

        private T element;

        private AvlTreeNode parent;

        private AvlTreeNode left;

        private AvlTreeNode right;

        // 计算当前树的高度
        public int getHeight() {
            int leftHeight = null != left ? left.getHeight() + 1 : 0;
            int rightHeight = null != right ? right.getHeight() + 1 : 0;
            return leftHeight > rightHeight ? leftHeight : rightHeight;
        }
        // 计算平衡因子
        public int getBalanceFactor() {
            int leftHeight = null != left ? left.getHeight() : -1;
            int rightHeight = null != right ? right.getHeight() : -1;
            return leftHeight - rightHeight;
        }
    }

仅用于自身学习记录,如有错误,请务必指出,不胜感激。日积跬步,以致千里。

你可能感兴趣的:(【数据结构】 AVL树)