【Java数据结构】AVL树(平衡二叉树)总结(增加,删除操作,四种旋转)

AVL树本质上还是一棵二叉搜索树,AVL = BST + 平衡操作

 

所以它的特点是: 

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

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

      3.树中的每个左子树和右子树都是AVL树

也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

为何引入AVL:

         对于一般的二叉搜索树(Binary Search Tree),其各操作的时间复杂度  O(log2n)  。但是,在某些极端的情况下(如在插入的序列是有序的时),二叉搜索树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n)。而AVL树会不断调整自身来达到左右子树高度差值不会超过1,这样就保证了其各个操作的时间复杂度保持在  O(log2n)  。

注:

1、AVL树是不是平衡树?平衡是什么意思?

         是平衡树,平衡:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1

2、AVL是不是搜索树?

         是搜索树,AVL = BST + 平衡操作,AVL具有BST全部特性。

3、AVL的几种旋转

         AVL有四中旋转操作。

4、AVL树时间复杂度。

         一棵AVL树有N个节点,高度可以保持在log2n,插入/删除/查找的时间复杂度也是log2n.

5、AVL树最差情况下,增删查需要旋转多少次?O(log2n)次

       O(log2n)次

       

 

平衡操作:节点的左右子树的高度差不能超过1,为了维持节点平衡 引入的四种节点旋转操作

 

1、左孩子的左子树太高 ----右旋转操作

 

child = node.left;
node,left = child.right;
child.right = node;
node和child的高度要更新!

 

2、右孩子的右子树太高 -----左旋转操作

child = node.right;
node.right = child.left;
child.left = node;
node和child的高度要更新

3、左孩子的右子树太高-----左平衡操作

 

 孩子节点先左旋,然后再右旋

 

4、右孩子的左子树太高-----右平衡操作

 

 孩子节点先右旋,然后再左旋

 

 

AVL树增加删除代码:

     节点的定义:

class AVLNode<T extends Comparable<T>>{
    private T data;
    private AVLNode<T> left;
    private AVLNode<T> right;
    private int height; // 保存当前节点的高度值

    public AVLNode(T data, AVLNode<T> left, AVLNode<T> right, int height) {
        this.data = data;
        this.left = left;
        this.right = right;
        this.height = height;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public AVLNode<T> getLeft() {
        return left;
    }

    public void setLeft(AVLNode<T> left) {
        this.left = left;
    }

    public AVLNode<T> getRight() {
        return right;
    }

    public void setRight(AVLNode<T> right) {
        this.right = right;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

}

 

          完整代码:

class AVLTree<T extends Comparable<T>>{
    private AVLNode<T> root;

    public AVLTree() {
        this.root = null;
    }

    /**
     * 递归实现AVL树的插入操作
     * AVL最差的情况,最差的情况下要旋转O(lgn)
     * @param data
     */
    public void insert(T data){
        this.root = insert(this.root, data);
    }
    private AVLNode<T> insert(AVLNode<T> root, T data) {
        if(root == null){
            return new AVLNode<>(data, null, null, 1);
        }

        if(root.getData().compareTo(data) > 0){
            root.setLeft(insert(root.getLeft(), data));
            // 左子树太高
            if(height(root.getLeft()) - height(root.getRight()) > 1){
                // 左孩子的左子树太高
                if(height(root.getLeft().getLeft())
                        >= height(root.getLeft().getRight())){
                    root = rightRotate(root);
                } else {
                    // 左孩子的右子树太高
                    root = leftBalance(root);
                }
            }
        } else {
            root.setRight(insert(root.getRight(), data));
            // 右子树太高
            if(height(root.getRight()) - height(root.getLeft()) > 1){
                // 右孩子的右子树太高
                if(height(root.getRight().getRight())
                        >= height(root.getRight().getRight())){
                    root = leftRotate(root);
                } else {
                    // 右孩子的左子树太高
                    root = rightBalance(root);
                }
            }
        }

        root.setHeight(maxHeight(root.getLeft(), root.getRight()) + 1);
        return root;
    }

    /**
     * 递归实现AVL树的删除操作
     * @param data
     */
    public void remove(T data){
        this.root = remove(this.root, data);
    }

    private AVLNode<T> remove(AVLNode<T> root, T data) {
        if(root == null){
            return null;
        }

        if(root.getData().compareTo(data) > 0){
            root.setLeft(remove(root.getLeft(), data));
            // #1
            if(height(root.getRight()) - height(root.getLeft()) > 1){
                if(height(root.getRight().getRight())
                        >= height(root.getRight().getLeft())){
                    // 右孩子的右子树太高
                    root = leftRotate(root);
                } else {
                    // 右孩子的左子树太高
                    root = rightBalance(root);
                }
            }
        } else if(root.getData().compareTo(data) < 0){
            root.setRight(remove(root.getRight(), data));
            // #2
            if(height(root.getLeft()) - height(root.getRight()) > 1){
                if(height(root.getLeft().getLeft())
                        >= height(root.getLeft().getRight())){
                    // 左孩子的左子树太高
                    root = rightRotate(root);
                } else {
                    // 左孩子的右子树太高
                    root = leftBalance(root);
                }
            }
        } else {
            if(root.getLeft() != null && root.getRight() != null){
                // #3
                if(height(root.getLeft()) >= height(root.getRight())){
                    // 用前驱节点代替
                    AVLNode<T> pre = root.getLeft();
                    while(pre.getRight() != null){
                        pre = pre.getRight();
                    }
                    root.setData(pre.getData());
                    root.setLeft(remove(root.getLeft(), pre.getData()));
                } else {
                    // 用后继节点代替
                    AVLNode<T> post = root.getRight();
                    while(post.getLeft() != null){
                        post = post.getLeft();
                    }
                    root.setData(post.getData());
                    root.setRight(remove(root.getRight(), post.getData()));
                }
            } else {
                if(root.getLeft() != null){
                    return root.getLeft();
                } else if(root.getRight() != null){
                    return root.getRight();
                } else {
                    return null;
                }
            }
        }

        // #4 在递归回溯的过程中更新节点的高度值
        root.setHeight(maxHeight(root.getLeft(), root.getRight()) + 1);
        return root;
    }


    /**
     * 以参数node为根节点进行左旋转操作,并把旋转后的子树的根节点返回
     * @param node
     * @return
     */
    private AVLNode<T> leftRotate(AVLNode<T> node){
        AVLNode<T> child = node.getRight();
        node.setRight(child.getLeft());
        child.setLeft(node);
        node.setHeight(maxHeight(node.getLeft(), node.getRight()) + 1);
        child.setHeight(maxHeight(child.getLeft(), child.getRight()) + 1);
        return child;
    }

    /**
     * 以参数node为根节点进行右旋转操作,并把旋转后的子树的根节点返回
     * @param node
     * @return
     */
    private AVLNode<T> rightRotate(AVLNode<T> node){
        AVLNode<T> child = node.getLeft();
        node.setLeft(child.getRight());
        child.setRight(node);
        node.setHeight(maxHeight(node.getLeft(), node.getRight()) + 1);
        child.setHeight(maxHeight(child.getLeft(), child.getRight()) + 1);
        return child;
    }

    /**
     * 以参数node为根节点进行左平衡操作,并把平衡后的子树的根节点返回
     * @param node
     * @return
     */
    private AVLNode<T> leftBalance(AVLNode<T> node){
        node.setLeft(leftRotate(node.getLeft()));
        return rightRotate(node);
    }

    /**
     * 以参数node为根节点进行右平衡操作,并把平衡后的子树的根节点返回
     * @param node
     * @return
     */
    private AVLNode<T> rightBalance(AVLNode<T> node){
        node.setRight(rightRotate(node.getRight()));
        return leftRotate(node);
    }

    private int maxHeight(AVLNode<T> node1, AVLNode<T> node2){
        int h1 = height(node1);
        int h2 = height(node2);
        return h1 > h2 ? h1 : h2;
    }

    private int height(AVLNode<T> node){
        return node == null ? 0 : node.getHeight();
    }
}

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值