【Java AVL树 图解+代码解析】简单理解

一、什么是AVL树

  • AVL树我们可以看作BST树的一个特殊情况。AVL树就是对BST树失衡的节点用旋转的方式让它达到平衡状态
  • 什么情况下为失衡?
    AVL树要求:任一节点,它的左右子树高度差不超过 1 ,那就是我们对失衡节点通过旋转让它平衡就好
    在这里插入图片描述
    例如上图:5 这个节点右子树高度为2,左子树高度为0,所以这个节点就失衡了。如果我们还是用BST树的方式去存储,效率很低,因为5-6-7构成了单链表。

二、创建AVL类和节点类

public class AVLtree<T extends Comparable> {
    private Entry<T> root;//根节点
    /**
     *AVL树的初始化
     */
    public AVLtree(Entry<T> root) {
        this.root = null;
    }
    static class Entry<E>{
        private E value;//数据域
        private Entry<E> left;//左孩子域
        private Entry<E> right;//右孩域
        private  int hight;//树的高度
        public Entry(E value, Entry<E> left, Entry<E> right, int hight) {
            this.value = value;
            this.left = left;
            this.right = right;
            this.hight = hight;
        }
        public Entry() {
            this(null,null,null,1);
        }

        public Entry(E value) {
            this(value,null,null,1);
        }
    }

三、四种旋转方式

在此之前我们要创建一个可以返回节点高度的函数

 /**
     * 返回最大高度
     * @param left
     * @param right
     * @return
     */
    public int maxHeight(Entry<T> left,Entry<T> right){
        return height(left)>height(right)? height(left):height(right);
    }
    /**
     *返回节点高度值
     * @param node
     * @return
     */
    private int height(Entry<T> node) {
        return node==null? 0:node.hight;
    }

一、左旋转


/**
     * 以node进行左旋转 节点失衡(右孩子的右支树太高)
     * @param node
     * @return child 返回的新根节点
     */
    public Entry<T>  leftRotate(Entry<T>node){
        Entry child = node.right;
        node.right = child.left;
        child.left = node;
        node.hight = maxHeight(node.left,node.right)+1;
        child.hight = maxHeight(child.left,child.right)+1;
        return child;
    }

二、右旋转

/**
     * 以node为根节点进行右旋转操作(左孩子的左支树太高)
     * @param node
     * @return child 返回新的根节点
     */
    public Entry<T> rightRotate(Entry<T>node){
        Entry child = node.left;
        node.left = child.right;
        child.right = node;
        node.hight = maxHeight(node.left,node.right)+1;
        child.hight = maxHeight(child.left,child.right)+1;
        return child;
    }

三、左-右旋转

 /**
     * 左-右 旋转  左孩子的右子树太高了
     */
    public Entry<T> leftBalance(Entry<T> node){
        node.left=leftRotate(node.left);
        return rightRotate(node);
    }

四、右-左旋转

 /**
     * 右-左 旋转  右孩子的左子树太高了
     */
    public Entry<T> rightBalance(Entry<T> node){
        node.right=leftRotate(node.right);
        return leftRotate(node);
    }

四、AVL树的插入删除

插入:

/**
     *AVL树的插入 (就是在BST树节点插入后加上判断条件就好)
     * @param value 插入的节点值
     */
    public void insert(T value) {
        root = insert(root,value );
    }
    public Entry<T> insert(Entry<T> root, T value){
        if (root == null){
            root = new Entry<>(value);
        }
        if (root.value.compareTo(value)>0){
            root.left = insert(root.left,value);
            //判断root节点是否失衡
            if (height(root.left)-height(root.right)>1){
                if (height(root.left.left)>height(root.left.right)){
                    //左孩子的右子树太高
                    root = rightRotate(root);
                }else {
                    //左孩子的左子树太高了
                    root = leftBalance(root);
                }
            }
        }else if (root.value.compareTo(value)<0){
            root.right = insert(root.right,value);
            //判断root节点是否失衡
            if (height(root.right)-height(root.left)>1){
                if (height(root.right.right)>height(root.right.left)){
                    //右孩子的左子树太高
                    root = leftRotate(root);
                }else {
                    //右孩子的右子树太高
                    root = rightBalance(root);
                }
            }
        }
        root.hight = maxHeight(root.left,root.right)+1;
        return root;
    }

删除:

 /**
     * AVL树的删除
     * @param
     */
    public void remove(T value){
        root = remove(root,value);
    }
    public Entry<T> remove(Entry<T> root,T value){
        if (root==null){
            return null;
        }
        if (root.value.compareTo(value)>0){
            //当前节点的值比待删节点的值大,则继续在左子树中寻找
            root.left = remove(root.left,value);
            if (height(root.right)-height(root.left)>1){
                if (height(root.right.right)>height(root.right.left)){
                    //右孩子的左子树太高
                    root = leftRotate(root);
                }else {
                    //右孩子的右子树太高
                    root = rightBalance(root);
                }
            }
        }else if (root.value.compareTo(value)<0){
            //当前节点的值比待删节点的值小,则继续在右子树中寻找
            root.right = remove(root.right,value);
            //判断root节点是否失衡
            if (height(root.left)-height(root.right)>1){
                if (height(root.left.left)>height(root.left.right)){
                    //左孩子的右子树太高
                    root = rightRotate(root);
                }else {
                    //左孩子的左子树太高了
                    root = leftBalance(root);
                }
            }
        }else {
            //已找到待删除节点root,考虑有两个孩子的情况(为了不让产生旋操作,哪边高删除那边)
            if (root.right!=null &&  root.left!=null){
                if (height(root.left)>=height(root.right)){
                //标记待删除节点的前驱节点,(左子树最大节点)
                Entry<T> pre = root.left;
                while (pre.right != null) {
                    //使pre指向待删节点的前驱节点
                    pre = pre.right;
                }
                root.value = pre.value;
                //继续递归删除节点的前驱节点
                root.left = remove(root.left, pre.value);
                }else {//删除节点的后驱(右子树最小的那个节点)
                    Entry<T> bre = root.right;
                    while (bre.right != null) {
                        //使bre指向待删节点的后驱节点
                        bre = bre.left;
                    }
                    root.value = bre.value;
                    //继续递归删除节点的后驱节点
                    root.right = remove(root.left, bre.value);
                }
            }else {
                if (root.left!=null){
                    return root.left;
                }else if (root.right!=null){
                    return root.right;
                }else {
                    return null;
                }
            }
        }
        root.hight = maxHeight(root.left,root.right)+1;
        return root;
    }

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值