美文网首页
AVL树(平衡二叉树)

AVL树(平衡二叉树)

作者: sadamu0912 | 来源:发表于2019-01-12 19:15 被阅读0次

AVL树本质上是一颗二叉查找树,但是它又具有以下特点:

  • 它是一棵空树或它的左右两个子树的高度差的绝对值不超过1
  • 并且左右两个子树都是一棵平衡二叉树
    什么叫平衡因子balance factor:
    结点的左子树的高度-右子树的高度 BalanceFactor = height(leftSubtree) − height(rightSubtree)

AVL 树如何保持平衡

靠以下4种旋转。

右旋转(叫顺时针旋转更贴切)(树结构是LL类型)

如下图


image.png

首先找到不平衡点T,然后找到T的不平衡方向的子节点L为轴(固定点),顺时针旋转,转动不平衡点T.T大于L,T成为L的右子节点。Y子树,大于L小于T,成为T的左子树。

左旋转(叫逆时针旋转更贴切)(树结构是RR类型) 正好是一个镜像反射
image.png

首先找到不平衡点T,然后找到T的不平衡方向的子节点R为轴(固定点),逆时针旋转,转动不平衡点T.T大于R,T成为R的左子节点。Y子树,大于T小于R,成为T的右子树。

右左旋转(树结构是RL类型)
image.png

首先找到不平衡点T,然后找到T的不平衡方向的子节点R 为轴(固定点),顺时针旋转L,L跑到T和R中间,L的右子树,大于L,小于R,成为R的左子树。然后以L为固定点,逆时针旋转T,T成为L的左子树,Y1成为T的右子树。

左右旋转(树结构是LR类型)
image.png

首先找到不平衡点T,然后找到T的不平衡方向的子节点R 为轴(固定点),逆时针旋转R,R 跑到T和L中间,R的左子树,大于L,小于T,成为L的右子树。然后以R为固定点,顺时针旋转T,T成为R的右子树,Y2成为T的左子树。

从下向上找不平衡线。 比如图3 ,不平衡线,v1---L---R---T .图4 的不平衡线是Y2---R--L---T
以上是四种基本的旋转类型。解决AVL树平衡的问题,基本思路是从下往上,依次找出不平衡点。然后使这个节点对应的树平衡,然后继续向上找不平衡的节点,再继续平衡,是个递归调用的过程。

以下是AVL树的实现代码:

/**
 * AVL树实现的map结构
 * @param <Key>
 * @param <Value>
 */
public class AVLTreeMap <Key extends Comparable,Value>{

    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    /**
     * 递归调用,先递归put方法,找到插入位置  返回一个节点return new TreeNode(key, value);
     * 假设前一步走得是【root.left = put(root.left, key, value);】这一句代码
     * 那【新节点D】 插入的是root的左节点【注意这个不是类所在的root,而是代码中的root】
     *  ******【后面就是不断update和balance .】***********************************
     * 1  【第一次递归========================】
     * update 方法  ,size左右子树的size+1 ,height 是左子树和右子树的高度
     * 最大值+1 。假设没有右子树,height =2
     * balance方法   直接return.
     *       root1
     *      /
     *    D
     * 2 【第二 次递归========================】
     *  假设原来第二次还是走得左侧。
     *  update之后是 root2的height=3
     *               root2
     *             /
     *        root1
     *      /
     *    D
     *    balance方法  调用rightRotate方法,改变高度和size
     * @param root
     * @param key
     * @param value
     * @return
     */
    private TreeNode put(TreeNode root, Key key, Value value) {
        if (root == null)  return new TreeNode(key, value);
        if (key.compareTo(root.key) < 0) root.left = put(root.left, key, value);
        else if (key.compareTo(root.key) > 0) 
                    root.right = put(root.right, key, value);
        else root.value = value;
        update(root);
        return balance(root);
    }

    private void update(TreeNode tree) {
        tree.size = size(tree.left) + size(tree.right) + 1;
        tree.height = Math.max(height(tree.left), height(tree.right)) + 1;
    }


    private TreeNode rightRotate(TreeNode oldRoot){
        TreeNode newRoot = oldRoot.left;
        oldRoot.left = newRoot.right ;
        update(oldRoot);
        newRoot.right = oldRoot ;
        update(newRoot);
        return  newRoot;
    }

    private TreeNode leftRotate(TreeNode oldRoot){
        TreeNode newRoot = oldRoot.right;
        oldRoot.right = newRoot.left ;
        update(oldRoot);
        newRoot.left = oldRoot ;
        update(newRoot);
        return  newRoot;
    }

    private TreeNode balance(TreeNode root) {
        if (height(root.left) - height(root.right) > 1) {
                if (height(root.left.left) > height(root.left.right)) { //LL
                root = rightRotate(root);
            }
            else { //LR
                root.left = leftRotate(root.left);
                root = rightRotate(root);
            }
        }
        else if (height(root.right) - height(root.left) > 1) {
            if (height(root.right.right) > height(root.right.left)) { //RR
                root = leftRotate(root);
            }
            else { //RL
                root.right = rightRotate(root.right);
                root = leftRotate(root);
            }
        }
        return root;
    }
    private TreeNode min(TreeNode root) {
        if (root.left == null) return root;
        return min(root.left);
    }

    public void remove(Key key) {
        remove(root, key);
    }

    /**
     * 删除方法和BST差不多,分四种情况讨论,左右子树都有的时候,要寻找继承者
     * @param root
     * @param key
     * @return
     */
    private TreeNode remove(TreeNode root, Key key) {
        if (root == null) return null;
        if (key.compareTo(root.key) < 0) {
            root.left = remove(root.left, key);
        }
        else if (key.compareTo(root.key) > 0) {
            root.right = remove(root.right, key);
        }
        else {
            if (root.left == null) return root.right;
            else if (root.right == null) return  root.left;
            else {
                TreeNode successor = min(root.right);
                Key tempKey = root.key;
                root.key = successor.key;
                root.value = successor.value;
                successor.key = tempKey;
                root.right = remove(root.right, tempKey);
            }
        }
        update(root);
        return balance(root);
    }

    private  class TreeNode {
        Key key;
        Value value ;
        TreeNode left,right;
        int height ,size ;

        public TreeNode(Key key, Value value) {
            this.key = key;
            this.value = value;
            this.height = 1;
            this.size =1;
        }
    }
    private TreeNode root;
    private int height(TreeNode tree){
        if (tree == null) return 0;
        return tree.height;
    }

    private int size(TreeNode tree) {
        if (tree == null) return 0;
        return tree.size;
    }

    public void displayTree(){
        Stack globalStack = new Stack();
        globalStack.push(root);
        int treeHeight = height(root);
        int nBlanks = (int) Math.pow(2d,(double)treeHeight);
        boolean isRowEmpty = false;
        System.out.println("=========================================================================");
        while(!isRowEmpty) {
            Stack localStack = new Stack();
            isRowEmpty = true;
            for (int  j =0;j<nBlanks;j++) {
                System.out.print(" ");
            }

            while (!globalStack.isEmpty()) {
                TreeNode temp = (TreeNode)globalStack.pop();
                if (temp!=null) {
                    System.out.print(temp.key);
                    localStack.push(temp.left);
                    localStack.push(temp.right);
                    if (temp.left != null || temp.right !=null) {
                        isRowEmpty = false;
                    }
                }
                else {
                    System.out.print("--");
                    localStack.push(null);
                    localStack.push(null);
                }
                for (int j = 0;j<nBlanks*2-2;j++) {
                    System.out.print(" ");
                }
            }
            System.out.println();
            nBlanks /= 2;
            while (!localStack.isEmpty()) {
                globalStack.push(localStack.pop());
            }
        }
        System.out.println("=========================================================================");
    }

}

相关文章

网友评论

      本文标题:AVL树(平衡二叉树)

      本文链接:https://www.haomeiwen.com/subject/bwscdqtx.html