Java高阶数据结构|AVL树

AVL树

对于二叉搜索树而言,当存在单分支有序结构时,查找效率会非常差,此时AVL树可以有效解决这个问题

AVL树的插入

  1. 按照二叉搜索树的方式插入新节点
java 复制代码
        TreeNode node=new TreeNode(val);
        if (root==null){
            root=node;
            return true;
        }
        TreeNode cur=root;
        TreeNode parent=null;
        while (cur!=null) {
            if (cur.val < val) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val == val) {
                return false;
            } else {
                parent = cur;
                cur = cur.left;
            }
        }
            if (parent.val<val){
                parent.right=node;
            }else{
                parent.left=node;
            }
            node.parent=parent;
            cur=node;
  1. 调整节点的平衡因子
java 复制代码
            //平衡因子的修改

            while(parent!=null){

                //先看cur是parent的左还是右  决定平衡因子是++还是--

                if(cur==parent.right){

                    //如果是右树,那么右树高度增加 平衡因子++

                    parent.bf++;
                }else {

                    //如果是左树,那么左树高度增加 平衡因子--

                    parent.bf--;
                }

AVL树的旋转

java 复制代码
    //检查当前的平衡因子 是不是绝对值 1  0  -1

                if (parent.bf==0){

                    //说明已经平衡了

                    break;
                } else if (parent.bf == 1 || parent.bf == -1) {

                    //继续向上去修改平衡因子

                    cur=parent;
                    parent=cur.parent;
                }else {
                    if (parent.bf==2){

                        //右树高-》需要降低右树的高度

                        if (cur.bf==1){

                            //左旋

                            rotateLeft(parent);
                        }else {

                            //cur.bf==-1(右左)

                            rotateRL(parent);
                        }
                    }else {

                        //parent.bf == -2 左树高-》需要降低左树的高度

                        if (cur.bf==-1){

                            //右旋

                            rotateRight(parent);
                        }else {

                            //cur.bf==1(左右)

                            rotateLR(parent);
                        }
                    }

                    //上述代码走完就平衡了

                    break;
                }
            }
  1. 新节点插入较高左子树的左侧---右单旋
java 复制代码
  private void rotateRight(TreeNode parent) {
        TreeNode subL=parent.left;
        TreeNode subLR=subL.right;
        parent.left=subLR;
        subL.right=parent;

        //没有subLR

        if(subLR!=null){
            subLR.parent=parent;
        }

        //必须先记录

        TreeNode Pparent=parent.parent;
        parent.parent=subL;

        //检查 当前是不是就是根节点

        if (root==parent){
            root=subL;
            root.parent=null;
        }else {

            //不是根节点,判断这棵子树是左子树还是右子树

            if (parent==Pparent.left){
                Pparent.left=subL;
            }else {
                Pparent.right=subL;
            }
            subL.parent=Pparent;
        }
        subL.bf=0;
        parent.bf=0;
    }

2.新节点插入较高右子树的右侧---左单旋

'

java 复制代码
private void rotateLeft(TreeNode parent) {
        TreeNode subR=parent.right;
        TreeNode subRL=subR.left;
        parent.right=subRL;
        subR.left=parent;
        if (subRL!=null){
            subRL.parent=parent;
        }
        TreeNode Pparent=parent.parent;
        if (root==parent){
            root=subR;
            root.parent=null;
        }else{
            if (parent==Pparent.left){
                Pparent.left=subR;
            }else {
                Pparent.right=subR;
            }
            subR.parent=Pparent;
        }
        subR.bf=0;
        parent.bf=0;
    }

3.新节点插入较高左子树的右侧:先左单旋再右单旋--左右双旋

java 复制代码
private void rotateLR(TreeNode parent) {
        TreeNode subL=parent.left;
        TreeNode subLR=subL.right;
        int bf=subLR.bf;
        rotateLeft(parent.left);
        rotateRight(parent);
        if (bf==-1){
            subL.bf=0;
            subLR.bf=0;
            parent.bf=1;
        }else if(bf==1){
            subL.bf=-1;
            subLR.bf =0;
            parent.bf=0;
        }
    }
  1. 新节点插入较高右子树的左侧---右左:先右单旋再左单旋--右左双旋
java 复制代码
 private void rotateRL(TreeNode parent) {
        TreeNode subR=parent.right;
        TreeNode subRL=subR.left;
        int bf= subRL.bf;
        rotateRight(parent.right);
        rotateLeft(parent);
        if (bf==-1){
            parent.bf=0;
            subRL.bf=0;
            subR.bf=1;
        }else if(bf==1) {// bf=0的情况在在上面的左旋与右旋已经调整完了
            parent.bf=-1;
            subRL.bf=0;
            subR.bf=0;
        }
    }

AVL树的验证

  1. 验证其为二叉搜索树

如果中序遍历可得到一个有序的序列,就说明为二叉搜索树

java 复制代码
//中序遍历的结果是有序的 就能说明当前树 一定是AVL树吗?  不一定的

    public void inorder(TreeNode root){
        if (root==null){
            return;
        }
        inorder(root.left);
        System.out.println(root.val+" ");
        inorder(root.right);
    }
  1. 验证其为平衡树

每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)

节点的平衡因子是否计算正确

java 复制代码
 public int height(TreeNode root){
        if (root==null){
            return 0;
        }
        int leftH=height(root.left);
        int rightH=height(root.right);
        return leftH > rightH ? leftH+1 : rightH+1;
    }
    public boolean isBalanced(TreeNode root){
        if(root==null)  return true;
        int leftH=height(root.left);
        int rightH=height(root.right);
        if (rightH-leftH!=root.bf){
            System.out.println("这个节点:"+root.val+"平衡因子异常");
            return false;
        }
        return Math.abs(leftH-rightH)<=1
                &&isBalanced(root.left)
                &&isBalanced(root.right);
    }
相关推荐
Doraemomo9 分钟前
数据结构-内存调试工具
数据结构
Mem0rin1 小时前
前缀和:中心下标与数组乘积
数据结构·算法
Lazionr1 小时前
list容器详解——双向链表的封装与使用
数据结构·c++·链表·list
漂流瓶jz1 小时前
UVA-12174 Shuffle的播放记录 题解答案代码 算法竞赛入门经典第二版
数据结构·c++·算法·图论·滑动窗口·算法竞赛入门经典·uva
lingran__1 小时前
C++ 高阶数据结构:红黑树万字详解|完整原理推导 + 插入实现 + 完整性校验【STL 底层】
数据结构·c++·面试·红黑树·二叉搜索树·平衡二叉树·stl底层
moonsims2 小时前
低空量子无人机
前端·数据结构
love_muming2 小时前
二叉树操作全解析:从递归到层序遍历
java·数据结构·算法·二叉树
白狐_79813 小时前
408数据结构第5章:二叉树遍历序列题——技巧、判断与真题型总结
数据结构
Forever Nore16 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
旖旎夜光18 小时前
LeetCode 11:盛最多水的容器(双指针问题) —— 题解
数据结构·c++·算法·leetcode·双指针