平衡二叉树(AVL树)

平衡二叉树(AVL)

问题引入:

        在二分搜索树(二叉排序树)中如果面对一个有序序列的插入,则会造成二分搜索树退化成为链表。例如对于序列:3,4,5,6,7依次插入二分搜索树时会形成一个单链表。

        此时虽然二分搜索树的插入与删除操作没有收到影响,但是搜索操作的效率是非常低,甚至不如链表的检索效率。

 

概念

平衡二叉树,也叫做平衡二叉搜索树或者AVL树

特点:树中任何一个结点的左右子树的高度相差不超过1

实现方法:AVL(算法),红黑树,替罪羊树,Treap,伸展树

实现平衡二叉树的方法

计算树高

结点的树高是进行平衡判断的基本条件

计算树高只需要计算其左右子树的高度的最大值,利用最大值加一即是当前结点的树高(递归)

    //计算当前结点的高度
    public int height(Node node){
        if (node == null){
            return 0;
        }
        //计算左右子树中高度较高的一边,并且加上当前的层数
        return Math.max(node.left == null?0:height(node.left) , node.right == null?0:height(node.right)) + 1;
​
    }

单旋转

单旋转分为左旋转与右旋转,进行左右旋转的条件需要根据当前结点左右子树的高来进行判断

左旋转

目的:降低右子树的高度

条件:当结点的右子树的高度 - 左子树的高度大于1时进行

步骤:

1.创建新结点,值为根结点的值 newNode.value = root.value
2.新结点的左子树指向根结点的左子树 newNode.left= root.left
3.新结点的右子树指向根结点的右子树的左子树 newNode.right = newNode.right.left
4.根结点的值替换为根结点右子树结点的值 root.value = root.right.value
5.根结点的右子树指向根结点右子树的右子树 root.right = root.right.right
6.根结点的左子树指向新结点 root.left = newNode

 

    //左旋转
    public void leftRotate(Node node){
        //创建新结点
        Node newNode = new Node(node.value);
        //新结点的左子树指向根结点左子树
        newNode.left = node.left;
        //新结点的右子树指向根结点右子树的左子树
        newNode.right = node.right.left;
        //根结点的值替换为根结点右子树结点的值
        node.value = node.right.value;
        //根结点的右子树指向根结点右子树的右子树
        node.right = node.right.right;
        //根结点的左子树指向新的结点
        node.left = newNode;
    }

右旋转

目的:降低左子树的高度

条件:当结点的右子树的高度 - 左子树的高度大于1时进行

步骤:

1.创建新结点,值为根结点的值 newNode.value = root.value
2.新结点的右子树指向根结点的右子树 newNode.right = root.right
3.新结点的左子树指向根结点的左子树的右子树 newNode.left= newNode.left.right
4.根结点的值替换为根结点左子树结点的值 root.value = root.left.value
5.根结点的左子树指向根结点左子树的左子树 root.left= root.left.left
6.根结点的右子树指向新结点 root.right= newNode

    //右旋转
    public void rightRotate(Node node){
        //创建新结点值为根节点的值
        Node newNode = new Node(node.value);
        //新结点的右子树指向根结点的右子树
        newNode.right = node.right;
        //新结点的左子树指向根结点左子树的右子树
        newNode.left = node.left.right;
        //根结点值替换为左子树结点的值
        node.value = node.left.value;
        //根结点左子树指向左子树的左子树
        node.left = node.left.left;
        //根结点的右子树指向新结点
        node.right = newNode;
    }

双旋转

单单凭借单旋转的左右旋转,遇到特殊情况时就无法进行平衡了

例如序列10,11,7,6,8,9在进行右旋转之后

可以发现在进行旋转之后还是存在不平衡的情况

解决办法就是双旋转

右旋转时:

1.进行右旋转时,若其结点的左子树的右子树高度大于左子树的左子树的高度

2.则先对其左子树进行左旋转

3.在对其进行右旋转

        //当前结点的左子树的高大于右子树的高时需要进行右旋转,height()方法计算当前结点的高度
        if ((height(node.left) - height(node.right) > 1)){
            //判断双旋转的条件,当左子树的右子树的高度大于左子树的右子树的高度时
            if (height((node.left.right)) > height(node.left.left)){
                //先对其左子树进行左旋转
                leftRotate(node.left);
            }
            //右旋转
            rightRotate(node);  
        }

左旋转时:

1.当进行左旋转时,若其右子树的左子树的高度大于其右子树的右子树的高度

2.则先对其右子树进行右旋转

3.再对原结点进行左旋转

        //当前结点的右子树的高大于左子树的高时需要进行左旋转
        if ((height(node.right) - height(node.left) > 1)){
            //判断双旋转的条件,右子树的左子树的高大于右子树的右子树的高
            if (height(node.right.left) > height(node.right.right)){
                //先对其右子树进行右旋转
                rightRotate(node.right);
            }
            //再对其进行左选择
            leftRotate(node);
        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值