AVL树实现

树结点:

public class myAVLTree {
    public TreeNode root;

    static class TreeNode {
        public TreeNode left;
        public TreeNode right;
        public TreeNode parent;
        public int val;
        public int bf; //平衡因子(blance factor)
        //bf = 右子树高度 - 左子树高度

        public TreeNode(int val) {
            this.val = val;
        }
    }
}

代码

//插入结点的原理和二叉搜索树一样
    public boolean insert(int val){
        TreeNode node = new TreeNode(val);
        if(root == null){
            root = node;
            return true;
        }
        TreeNode cur = root;
        TreeNode parent = null;
        while(cur != null){
            if(val > cur.val){
                parent = cur;
                cur = cur.right;
            }else if(val < cur.val){
                parent = cur;
                cur = cur.left;
            }else{
                //相等
                return false;
            }
        }
        //插入到叶子结点
        if(parent.val < val){
            node = parent.right;
        }else{
            node = parent.left;
        }

        //平衡因子修改
        node.parent = parent;
        cur = node;
        while(parent != null){
            if(cur == parent.right){
                //如果结点插在父结点右边,则右树高度增加,平衡因子++
                parent.bf++;
            }else{
                //如果结点插在父结点左边,则左树高度增加,平衡因子--
                parent.bf--;
            }
            //检查当前的平衡因子
            if(parent.bf == 0){
                break;
            }else if(parent.bf == 1 || parent.bf == -1){
                //继续向上检查平衡因子 可能存在不平衡的情况
                node = parent;
                parent = parent.parent;
            }else{
                if(parent.bf == 2){
                    if(cur.bf == 1){
                        //右树高度高了,需要降低右树高度,进行左旋操作
                        RotateL(parent);
                    }else{
                        //cur.bf == -1
                        RotateRL(parent);
                    }
                }else{
                    //parent.bf == -2
                    //左树高度高了,需要降低左树高度
                    if(cur.bf == -1){
                        //右旋
                        RotateR(parent);
                    }else{
                        //cur.bf == 1
                        //左右双璇
                        RotateLR(parent);
                    }
                }
                break;
            }
        }
        return true;
    }

左单旋

两种情况

1.定义结点时TreeNode subR = parent.right  TreeNode subRL = subR.left

当subRL != null时

2.subRL == null时

1.subRL != null

//左单旋
    public void RotateL(TreeNode parent){
        TreeNode subR = parent.right;
        TreeNode subRL = subR.left;
        
        //提前定义好父亲结点的父结点,因为后面父亲结点的指向就被改变了
        TreeNode pParent = parent.parent;

        subR.left = parent;
        parent.right = subRL;
        //与右旋一样的情况 subRL可能为null
        if(subRL != null){
            subRL.parent = parent;
        }
        parent.parent = subR;

        //判断是否是根结点
        if(parent == root){
            root = subR;
            root.parent = null;
        }else{
            if(pParent.left == parent){
                pParent.left = subR;
            }else{
                parent.right = subR;
            }
        }
        //改变平衡因子
        parent.bf = 0;
        subR.bf = 0;
    }

2.subRL==null

//右旋
    public void RotateR(TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;

        //父结点的上面还存在着他的父节点
        TreeNode pParent = parent.parent;


        //进行右旋操作
        subL.right = parent;

        //注意这里还有一种情况:subLR为null
        parent.left = subLR;
        if(subLR != null){
            subLR.parent = parent;
        }

        parent.parent = subL;

        if(parent == root){
            //判断是否为根节点
            subL = root;
            root.parent = null;
        }else{
            if(pParent.left == parent){
                pParent.left = subL;
            }else{
                parent.right = subL;
            }
        }
        //将现在的父结点指向原来父亲结点的父结点
        subL.parent = pParent;
        //修改平衡因子
        subL.bf = 0;
        parent.bf = 0;
    }

右单璇

和左单旋一样,也是有两种情况

1.subLR != null

2.subLR == null

  //右旋
    public void RotateR(TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;

        //父结点的上面还存在着他的父节点
        TreeNode pParent = parent.parent;


        //进行右旋操作
        subL.right = parent;

        //注意这里还有一种情况:subLR为null
        parent.left = subLR;
        if(subLR != null){
            subLR.parent = parent;
        }

        parent.parent = subL;

        if(parent == root){
            //判断是否为根节点
            subL = root;
            root.parent = null;
        }else{
            if(pParent.left == parent){
                pParent.left = subL;
            }else{
                parent.right = subL;
            }
        }
        //新父结点指向原父结点的父结点
        subL.parent = pParent;
        //修改平衡因子
        subL.bf = 0;
        parent.bf = 0;
    }

双旋

上面的单旋模式中,我们可以总结规律-----当前结点的平衡因子和父结点的平衡因子的符号总是相同的,而双旋模式就出现在当前结点的平衡因子和父亲结点的平衡因子相反的情况且父亲的平衡因子=-2or2,这种情况下无论你左旋还是右旋,只旋转一次的话是得不到高度平衡的,故需要旋转两次

左右双旋

当subLR.bf=1时

2.subLR.bf=-1时

//左右双璇
    public void RotateLR(TreeNode parent){
        TreeNode subL = parent.left;
        TreeNode subLR = subL.right;
        int bf = subLR.bf;
        //先左旋
        RotateL(parent.left);
        //再右旋
        RotateR(parent);
        //subLR的平衡因子影响着结点的平衡因子
        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;
        }
    }

右左双旋

subRL.bf=1时

subRL=-1时

public  void RotateRL(TreeNode parent){
        TreeNode subR = root.right;
        TreeNode subRL = subR.left;
        int bf = subRL.bf;
        //先右旋
        RotateR(parent.right);
        //再左旋
        RotateL(parent);
        if(bf == 1){
            subRL.bf = 0;//不变的
            subR.bf = 0;
            parent.bf = -1;
        }else if(bf == -1){
            subRL.bf = 0;
            subR.bf = 1;
            parent.bf = 0;
        }
    }
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值