10.AVL树

 10.AVL树

AVL 树(平衡二叉搜索树)
        二叉搜索树在插入和删除时,节点可能失衡
        如果在插入和删除时通过旋转,始终让二叉搜索树保持平衡,称为自平衡的二叉搜索树
        AVL是自平衡二又搜索树的实现之一

        如果一个节点的左右孩子,高度差超过1,则此节点失衡,才需要旋转。

10.1 获取高度

 //处理节点高度
        private int haight(AVLNode node) {
            return node == null ? 0 : node.height;
        }

10.2更新高度

  //增、删、旋转更新节点高度
        //最大高度+1
        public void updateHeight(AVLNode treeNode) {
            treeNode.height=Integer.max(haight(treeNode.left),haight(treeNode.right))+1;
        }

10.1 旋转

10.1.1 平衡因子

平衡因子:一个节点左子树高度-右子树高度所得结果
 小于1平衡:(0,1,-1)
 大于1不平衡
       >1:左边高
       <-1:右边高

        


public int bf(AVLNode avlNode){
  return haight(avlNode.left)-haight(avlNode.right);
}

10.1.2 四种失衡情况

 LL
    -失衡节点的 bf >1,即左边更高
    -失衡节点的左孩子的bf>=0即左孩子这边也是左边更高或等
    一次右旋可以恢复平衡
 LR
    -失衡节点的 bf >1,即左边更高
    -失衡节点的左孩子的bf<0 即左孩子这边是右边更高
    左子节点先左旋,将树修正为LL情况,
    然后失衡节点再右旋,恢复平衡
RL
    -失衡节点的 bf <-1,即右边更高
    -失衡节点的右孩子的bf>0,即右孩子这边左边更高
    右子节点先右旋,将树修正为RR情况,
    然后失衡节点再左旋,恢复平衡
 RR
    -失衡节点的 bf<-1,即右边更高
    -失衡节点的右孩子的bf<=0,即右孩子这边右边更高或等高
    一次左旋可以恢复平衡
  //右旋

    /**
     * @Description 返回旋转后的节点
     * @Param [avlNode] 需要旋转的节点
     **/

    private AVLNode rightRotate(AVLNode redNode) {
        AVLNode yellowNode = redNode.left;
        /*
         *黄色节点有右子节点,给右子节点重新找父级节点
         *由于二叉搜索树特性,某个节点的左子节点必定小于 本身,右子节点必定大于本身
         * 故:yelllow的右子节点必定大于yellow且小于rea,
         *    所以,gree可以作为red的左子结点
         * */
        /*
        AVLNode greeNode = yellowNode.right;
        redNode.left = greeNode;
        */
        redNode.left = yellowNode.right;
        yellowNode.right = redNode;
        //更新高度,红色和黄色都会改变
        updateHeight(redNode);
        updateHeight(yellowNode);
        return yellowNode;
    }

    //左旋
    private AVLNode leftRotate(AVLNode redNode) {
        //左旋和右旋操作相反
        AVLNode yellowNode = redNode.right;
        //处理yellow的子节点
        redNode.right = yellowNode.left;
        //yellow变为跟,原red比yellow小,为yellow的left
        yellowNode.left=redNode;
        updateHeight(redNode);
        updateHeight(yellowNode);
        return yellowNode;
    }
    /*
    * LR
            -失衡节点的 bf >1,即左边更高
            -失衡节点的左孩子的bf<0 即左孩子这边是右边更高
            左子节点先左旋,将树修正为LL情况,
            然后失衡节点再右旋,恢复平衡
    * */
    //先左旋再右旋
    private AVLNode leftRightRotate(AVLNode node) {
        //修正左子结点LL
        node.left = leftRotate(node.left);
       return rightRotate(node);
    }
    /*
    *   RL
            -失衡节点的 bf <-1,即右边更高
            -失衡节点的右孩子的bf>0,即右孩子这边左边更高
            右子节点先右旋,将树修正为RR情况,
            然后失衡节点再左旋,恢复平衡
    * */
    //先右旋再左旋
    private AVLNode rightLeftRotate(AVLNode node) {
        //修正右子节点为RR
        node.right= rightRotate(node.left);
        return leftRotate(node);
    }

10.1.3 返回一个平衡后的树

//检查节点是否失衡,重新平衡
    private AVLNode checkBalance(AVLNode node) {
        if (node == null) {
            return null;
        }
        //获取该节点的平衡因子
        int bf = bf(node);
        if (bf > 1) {
            //左边更高的两种情况根据 左子树平衡因子判定
            int leftBf = bf(node.left);
            if (leftBf >= 0) {
                //左子树左边高 LL 右旋  考虑到删除时等于0也应该右旋
                return rightRotate(node);
            } else {
                //左子树右边更高 LR
                return leftRightRotate(node);
            }
        } else if (bf < -1) {
            int rightBf = bf(node.right);
            if (rightBf <= 0) {
                //右子树左边更高 RR 虑到删除时等于0也要左旋
                return leftRotate(node);
            } else {
                //右子树右边更高  RL
                return rightLeftRotate(node);
            }
        }
        return node;
    }

10.2 新增

 public void put(int key, Object value){
        doPut(root,key,value);
    }
    //找空位并添加新的节点
    private AVLNode doPut(AVLNode node, int key, Object value) {
        /*
        * 1.找到空位,创建新节点
        * 2.key 已存在 更新位置
        * 3.继续寻找
        *  */
        //未找到
        if (node ==null){
            return new AVLNode(key,value);
        }
        //找到了节点 重新赋值
        if(key ==node.key){
            node.value=value;
            return node;
        }
        //继续查找
        if(key < node.key){
            //继续向左,并建立父子关系
            node.left= doPut(node.left,key,value);
        }else{
            //向右找,并建立父子关系
          node.right=  doPut(node.right,key,value);
        }
        //更新节点高度
        updateHeight(node);
        //重新平衡树
       return checkBalance(node);

    }

10.3 删除

//删除
    public void remove(int key) {
        root = doRemove(root, key);
    }
    private AVLNode doRemove(AVLNode node, int key) {
        //1. node==null
        if (node == null) {
            return node;
        }
        //2.未找到key
        if (key < node.key) {
            //未找到key,且key小于当前节点key,继续向左
            node.left = doRemove(node.left, key);
        } else if (key > node.key) {
            //向右找
            node.right = doRemove(node.right, key);
        } else {
            //3.找到key
            if (node.left == null && node.right == null) {
                //3.1 没有子节点
                return null;
            } else if (node.left != null && node.right == null) {
                //3.2 一个子节点(左节点)
                node = node.left;
            } else if (node.left == null && node.right != null) {
                //3.2 一个子节点(右节点)
                node = node.right;
            } else {
                //3.3 两个子节点
                //找到他最小的后继节点,右子树向左找到底
                AVLNode s=node;
                while (s.left!=null){
                    s=s.left;
                }
                //s即为后继节点,将节点删除并重新修正右子树
                s.right=doRemove(s.right,s.key);
                //左子树为s.left,右子树为原删除节点的左子树
                s.left=node.left;
                node=s;
            }
        }
        //4.更新高度
        updateHeight(node);
        //5.检查是否失衡
        return checkBalance(node);
    }

10.4 整体代码

package org.alogorithm.tree.AVLTree;

public class AVLTree {
    static class AVLNode {
        int key;
        int height = 1;//高度初始值1
        AVLNode left, right;
        private AVLNode root;
        Object value;

        public AVLNode(int key, Object value) {
            this.key = key;
            this.value = value;
        }

        public AVLNode(int key, AVLNode left, AVLNode right, AVLNode root) {
            this.key = key;
            this.left = left;
            this.right = right;
            this.root = root;
        }


    }

    //处理节点高度
    private int haight(AVLNode node) {
        return node == null ? 0 : node.height;
    }

    //增、删、旋转更新节点高度
    //最大高度+1
    public void updateHeight(AVLNode treeNode) {
        treeNode.height = Integer.max(haight(treeNode.left), haight(treeNode.right)) + 1;
    }

    /*
    平衡因子:一个节点左子树高度-右子树高度所得结果
     小于1平衡:(0,1,-1)
     大于1不平衡
         >1:左边高
         <-1:右边高

     */
    public int bf(AVLNode avlNode) {
        return haight(avlNode.left) - haight(avlNode.right);
    }
    //四种失衡情况
        /*
        LL
            -失衡节点的 bf >1,即左边更高
            -失衡节点的左孩子的bf>=0即左孩子这边也是左边更高或等
            一次右旋可以恢复平衡
        LR
            -失衡节点的 bf >1,即左边更高
            -失衡节点的左孩子的bf<0 即左孩子这边是右边更高
            左子节点先左旋,将树修正为LL情况,
            然后失衡节点再右旋,恢复平衡
        RL
            -失衡节点的 bf <-1,即右边更高
            -失衡节点的右孩子的bf>0,即右孩子这边左边更高
            右子节点先右旋,将树修正为RR情况,
            然后失衡节点再左旋,恢复平衡
        RR
            -失衡节点的 bf<-1,即右边更高
            -失衡节点的右孩子的bf<=0,即右孩子这边右边更高或等高
            一次左旋可以恢复平衡
*/

    //右旋

    /**
     * @Description 返回旋转后的节点
     * @Param [avlNode] 需要旋转的节点
     **/

    private AVLNode rightRotate(AVLNode redNode) {
        AVLNode yellowNode = redNode.left;
        /*
         *黄色节点有右子节点,给右子节点重新找父级节点
         *由于二叉搜索树特性,某个节点的左子节点必定小于 本身,右子节点必定大于本身
         * 故:yelllow的右子节点必定大于yellow且小于rea,
         *    所以,gree可以作为red的左子结点
         * */
        /*
        AVLNode greeNode = yellowNode.right;
        redNode.left = greeNode;
        */
        redNode.left = yellowNode.right;
        yellowNode.right = redNode;
        //更新高度,红色和黄色都会改变
        updateHeight(redNode);
        updateHeight(yellowNode);
        return yellowNode;
    }

    //左旋
    private AVLNode leftRotate(AVLNode redNode) {
        //左旋和右旋操作相反
        AVLNode yellowNode = redNode.right;
        //处理yellow的子节点
        redNode.right = yellowNode.left;
        //yellow变为跟,原red比yellow小,为yellow的left
        yellowNode.left = redNode;
        updateHeight(redNode);
        updateHeight(yellowNode);
        return yellowNode;
    }

    /*
    * LR
            -失衡节点的 bf >1,即左边更高
            -失衡节点的左孩子的bf<0 即左孩子这边是右边更高
            左子节点先左旋,将树修正为LL情况,
            然后失衡节点再右旋,恢复平衡
    * */
    //先左旋再右旋
    private AVLNode leftRightRotate(AVLNode node) {
        //修正左子结点LL
        node.left = leftRotate(node.left);
        return rightRotate(node);
    }

    /*
    *   RL
            -失衡节点的 bf <-1,即右边更高
            -失衡节点的右孩子的bf>0,即右孩子这边左边更高
            右子节点先右旋,将树修正为RR情况,
            然后失衡节点再左旋,恢复平衡
    * */
    //先右旋再左旋
    private AVLNode rightLeftRotate(AVLNode node) {
        //修正右子节点为RR
        node.right = rightRotate(node.left);
        return leftRotate(node);
    }

    //检查节点是否失衡,重新平衡
    private AVLNode checkBalance(AVLNode node) {
        if (node == null) {
            return null;
        }
        //获取该节点的平衡因子
        int bf = bf(node);
        if (bf > 1) {
            //左边更高的两种情况根据 左子树平衡因子判定
            int leftBf = bf(node.left);
            if (leftBf >= 0) {
                //左子树左边高 LL 右旋  考虑到删除时等于0也应该右旋
                return rightRotate(node);
            } else {
                //左子树右边更高 LR
                return leftRightRotate(node);
            }
        } else if (bf < -1) {
            int rightBf = bf(node.right);
            if (rightBf <= 0) {
                //右子树左边更高 RR 虑到删除时等于0也要左旋
                return leftRotate(node);
            } else {
                //右子树右边更高  RL
                return rightLeftRotate(node);
            }
        }
        return node;
    }

    AVLNode root;

    public void put(int key, Object value) {
        doPut(root, key, value);
    }

    //找空位并添加新的节点
    private AVLNode doPut(AVLNode node, int key, Object value) {
        /*
         * 1.找到空位,创建新节点
         * 2.key 已存在 更新位置
         * 3.继续寻找
         *  */
        //未找到
        if (node == null) {
            return new AVLNode(key, value);
        }
        //找到了节点 重新赋值
        if (key == node.key) {
            node.value = value;
            return node;
        }
        //继续查找
        if (key < node.key) {
            //继续向左,并建立父子关系
            node.left = doPut(node.left, key, value);
        } else {
            //向右找,并建立父子关系
            node.right = doPut(node.right, key, value);
        }
        //更新节点高度
        updateHeight(node);
        //重新平衡树
        return checkBalance(node);
    }

    //删除
    public void remove(int key) {
        root = doRemove(root, key);
    }
    private AVLNode doRemove(AVLNode node, int key) {
        //1. node==null
        if (node == null) {
            return node;
        }
        //2.未找到key
        if (key < node.key) {
            //未找到key,且key小于当前节点key,继续向左
            node.left = doRemove(node.left, key);
        } else if (key > node.key) {
            //向右找
            node.right = doRemove(node.right, key);
        } else {
            //3.找到key
            if (node.left == null && node.right == null) {
                //3.1 没有子节点
                return null;
            } else if (node.left != null && node.right == null) {
                //3.2 一个子节点(左节点)
                node = node.left;
            } else if (node.left == null && node.right != null) {
                //3.2 一个子节点(右节点)
                node = node.right;
            } else {
                //3.3 两个子节点
                //找到他最小的后继节点,右子树向左找到底
                AVLNode s=node;
                while (s.left!=null){
                    s=s.left;
                }
                //s即为后继节点,将节点删除并重新修正右子树
                s.right=doRemove(s.right,s.key);
                //左子树为s.left,右子树为原删除节点的左子树
                s.left=node.left;
                node=s;
            }
        }
        //4.更新高度
        updateHeight(node);
        //5.检查是否失衡
        return checkBalance(node);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值