平衡二叉查找树(AVL)的插入

本文详细阐述了平衡二叉查找树的插入操作,并通过四种旋转(LL、RR、LR、RL)确保树的平衡性。提供了Java实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平衡二叉查找树的概念就不多介绍了,这边主要说明一下如何进行插入操作
在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。那么调整不平衡树的基本方法就是: 旋转 。 下面我们归纳一下平衡旋转的4种情况
1) 绕某元素左旋转 LL(右子树出现右不平衡)
这里写图片描述
分析一下:在插入数据100之前,左图中的 ST树只有80节点的平衡因子是-1(左高-右高),但整棵树还是平衡的。加入100之后,80节点的平衡因子就成为了-2,此时平衡被破坏。需要左旋转成右图。
当树中节点X的右孩子的右孩子上插入新元素,且平衡因子从-1变成-2后,就需要绕节点X进行左旋转。
2) 绕某元素右旋转 RR(左子树出现左不平衡)
这里写图片描述

当树中节点X的左孩子的左孩子上插入新元素,且平衡因子从1变成2后,就需要绕节点X进行右旋转。
3) 绕某元素的左子节点左旋转,接着再绕该元素自己右旋转。 此情况下就是左旋与右旋 的结合,具体操作时可以分解成这两种操作,只是围绕点不一样而已。LR(左子树出现右不平衡)
这里写图片描述

当树中节点X的左孩子的右孩子上插入新元素,且平衡因子从1变成2后,就需要先绕X的左子节点Y左旋转,接着再绕X右旋转
4) 绕某元素的右子节点右旋转,接着再绕该元素自己左旋转。 此情况下就是 右旋与左旋 的结合,具体操作时可以分解 成这两种操作,只是围绕点不一样而已 。RL(右子树左不平衡)
这里写图片描述
当树中节点X的右孩子的左孩子上插入新元素,且平衡因子从-1变成-2后,就需要 先绕X的右子节点Y右旋转,接着再绕X左旋转

附上这几种操作的java版本的代码,代码自己用不同的用例测过,如果有什么地方没有考虑到,欢迎指正^0^

import java.util.ArrayList;
import java.util.List;


public class AVL {

    class TreeNode{
        int value;
        int bf;
        TreeNode left,right;
        TreeNode(int v){
            value = v;
            bf = 0;
        }
    }
    public TreeNode buildTree(int[] nums){
        if(nums.length == 0) return null;
        TreeNode PRoot = new TreeNode(0);
        TreeNode root = new TreeNode(nums[0]);
        //为了能让后面可以改变root的地址而设
        PRoot.left = root;
        for(int i = 1; i < nums.length ; i++){
            insertTree(nums[i],PRoot);
        }
        return root;
    }

    public void insertTree(int num,TreeNode PRroot){
        if(PRroot.left == null) 
            return;
        TreeNode A=PRroot.left , B=PRroot.left ;
        TreeNode insertNode = new TreeNode(num); 
        TreeNode temp = PRroot.left ;
        TreeNode AFather = null,tempFather = null;

        while(temp != null){
            //找到从下到上最近的可能出现不平衡的节点
            if(temp.bf != 0){
                A = temp;
                AFather = tempFather;
            }
            tempFather = temp;
            if(num < temp.value)
                temp = temp.left;
            else
                temp = temp.right;
        }
        //插入孩子
        if(num > tempFather.value)
            tempFather.right = insertNode;
        else
            tempFather.left = insertNode;
        adjustBalance(A,AFather,insertNode,PRroot);
//      printTree(PRroot);
    }
    public TreeNode updateBF(TreeNode insert,TreeNode node){
        if(insert.value < node.value){
            node.bf +=1;
            return node.left;
        }
        else {
            node.bf -= 1;
            return node.right;
        }
    }

    public void adjustBalance(TreeNode A,TreeNode AFather,TreeNode insert,TreeNode PRoot){
        //确定B节点,修改A的bf
        TreeNode B = updateBF(insert,A);;
        //B不是插入点则也需要更新B的bf
        System.out.println("B.value= " + B.value);
        //在原来都平衡的一边加上一个值,A就会是root,所以要修改从B到插入节点之间的bf值
        TreeNode temp = B;
        while(temp.value != insert.value){
            updateBF(insert,temp);
            if(insert.value < temp.value)
                temp = temp.left;
            else 
                temp = temp.right;
        }


        //LL
        if(A.bf == 2 && B.bf == 1){
            A.left = B.right;
            B.right = A;
            A.bf = 0;
            B.bf = 0;
            updateChild(AFather,A,B,PRoot);

        }
        //RR
        else if(A.bf == -2 && B.bf == -1){
            A.right = B.left;
            B.left = A;
            A.bf = 0;
            B.bf = 0;
            updateChild(AFather,A,B,PRoot);
        }
        //LR
        else if(A.bf == 2 && B.bf == -1){
            TreeNode C = B.right;
            //先往左转成LL
            B.right = C.left;
            C.left = B;
            //LL
            A.left = C.right;
            C.right = A;
            //插入的点如果比C大最后会落在A的左边,比C小会落在B的右边
            //A的右边 和B的左边一定有元素
            if(insert.value > C.value){
                A.bf = 0;
                B.bf = -1;
                C.bf = 0;
            }
            else if(insert.value < C.value) {
                A.bf = 1;
                B.bf = 0;
                C.bf = 0;   
            }
            //插入点就是C的话
            else{
                A.bf = 0;
                B.bf = 0;
            }
            updateChild(AFather,A,C,PRoot);
        }
        //RL
        else if(A.bf == -2 && B.bf == 1){
            TreeNode C = B.left;
            //先转成RR
            B.left = C.right;
            C.right = B;
            //RR
            A.right= C.left;
            C.left = A;
            //插入的点如果比C大最后会落在B的左边,比C小会落在A的右边
            //因为B右边和A的左边一定会有元素
            if(insert.value > C.value){
                B.bf = 0;
                A.bf = 1;
                C.bf = 0;
            }
            else if(insert.value < C.value){
                A.bf = 0;
                B.bf = -1;
                C.bf = 0;
            }
            //C就是要插入的元素
            else{
                A.bf = 0;
                B.bf = 0;
            }
            updateChild(AFather,A,C,PRoot);
        }
    }
    public void updateChild(TreeNode father,TreeNode originChild,TreeNode newChild,TreeNode PRoot){
        if(father == null)
            PRoot.left = newChild;
        else if(originChild == father.left)
            father.left = newChild;
        else
            father.right = newChild;
    }
    public void printTree(TreeNode tree){
        if(tree.left == null) return;
        List<TreeNode> nodes = new ArrayList<TreeNode>();
        nodes.add(tree.left);
        printNode(nodes,"value");
        System.out.println("***************");
        printNode(nodes,"bf");
        System.out.println("#################");
    }

    public void printNode(List<TreeNode> nodes,String type){
        if(nodes.size() == 0) return;
        List<TreeNode> childs = new ArrayList<TreeNode>();
        for(TreeNode node:nodes){
            if(type.equals("value"))
                System.out.print(node.value + " ");
            else
                System.out.print(node.bf + " ");
            if(node.left != null)
                childs.add(node.left);
            if(node.right != null)
                childs.add(node.right);
        }
        System.out.println();
        printNode(childs,type);
    }

    public static void main(String[] args){
        int[] nums={10,20,29,24,12,53,45,90,100,290,28};
        AVL avl = new AVL();
        TreeNode tree = avl.buildTree(nums);
        avl.printTree(tree);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值