平衡二叉树AVL

1. 平衡二叉树

  • 平衡二叉树解决了二叉排序树退化为单链表的问题;
  • 平衡二叉树也称为自平衡二叉搜索树或AVL树;
  • AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis;
  • 平衡二叉树本质还是二叉排序树;
  • 平衡二叉树的限制:空树或左右子树高度差的绝对值不超过1;
  • 平衡因子:左子树高度-右子树高度,取值范围为{-1,0,1};
  • 调整最小不平衡子树使得整个二叉排序树平衡;
  • 查找时间复杂度:O(log2n),借助递推公式:Nh=Nh-1+Nh-2+1;

在这里插入图片描述
在这里插入图片描述

1.1 如何调整最小不平衡子树

  • 四种不平衡子树:LL、LR、RL、RR,分别表示1)在root树的左子节点的左子树插入节点导致不平衡;1)在root树的左子节点的右子树插入节点导致不平衡;1)在root树的右子节点的左子树插入节点导致不平衡;1)在root树的右子节点的右子树插入节点导致不平衡;
    在这里插入图片描述
  • LL、RR为两种基本情况,对应解决方案为单旋转,分别为:右旋、左旋;
    LL:树右旋
    在这里插入图片描述
    RR:树左旋
    在这里插入图片描述
  • LR、RL为两种复杂情况,对应解决方案为双旋转,分别为:先左旋再右旋、先右旋再左旋;
    LR:左子树左旋+树右旋
    在这里插入图片描述

在这里插入图片描述
RL:右子树右旋+树左旋
在这里插入图片描述
在这里插入图片描述

1.2 左旋、右旋代码实现

左旋:
在这里插入图片描述

/**
* 左旋
*/
private void leftRotate() {
	// 1.创建新节点,与当前根节点值一致
	TreeNode newNode = new TreeNode(val);
	// 2.新节点的左子树为root的左子树
	newNode.left=left;
	// 3. 新节点的右子树为root的右子树的左子树
	newNode.right=right.left;
	// 4.root的值替换为其右子节点的值
	val=right.val;
	// 5.root的右子树为右子树的右子树
	right=right.right;
	// 6.当前节点的左子树为新节点
	left=newNode;
}

右旋:
在这里插入图片描述

/**
 * 右旋
 */
private void rightRotate() {
    // 1.创建新节点,与当前根节点值一致
    TreeNode newNode = new TreeNode(val);
    // 2.新节点的右子树为root的右子树
    newNode.right=right;
    // 3. 新节点的左子树为root的左子树的右子树
    newNode.left=left.right;
    // 4.root的值替换为其左子节点的值
    val=left.val;
    // 5.root的左子树为左子树的左子树
    left=left.left;
    // 6.当前节点的右子树为新节点
    right=newNode;
}

1.3 解决导致不平衡的四种情况

class AVLTree{
    public TreeNode root;

    public AVLTree(TreeNode root){
        this.root=root;
    }

    public AVLTree() {

    }


    /**
     * 插入节点
     */
    public void insert(TreeNode node){
        // 根节点
        if (root==null){
            root=node;
        }else{
            root.insert(node);
        }
    }

    /**
     * 中序遍历
     */
    public void inOrder(){
        if (root==null){
            return;
        }
        root.inOrder();
    }

    /**
     * 层序遍历
     */
    public void levelOrder(){
        if (root==null){
            return;
        }
        root.levelOrder();
    }
}

class TreeNode{
    public int val;
    public TreeNode left;
    public TreeNode right;

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

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

    /**
     * 返回以当前节点为根节点的树的高度
     * @return
     */
    public int getHeight(){
        return Math.max(left==null?0:left.getHeight(),right==null?0:right.getHeight())+1;
    }

    /**
     * 返回以当前节点左子树的高度
     * @return
     */
    public int getLeftHeight(){
        if (left==null){
            return 0;
        }
        return left.getHeight();
    }

    /**
     * 返回以当前节点右子树的高度
     * @return
     */
    public int getRightHeight(){
        if (right==null){
            return 0;
        }
        return right.getHeight();
    }

    @Override
    public String toString() {
        return "TreeNode{" +
                "val=" + val +
                '}';
    }

    /**
     * 新增节点,满足二叉排序树要求
     * @param node
     */
    public void insert(TreeNode node) {
        if (node==null){
            return;
        }

        // 比较当前节点与node节点的大小关系
        if (node.val<val){
            if (left==null){
                left=node;
            }else{
                left.insert(node);
            }
        }else{
            if (right==null){
                right=node;
            }else{
                right.insert(node);
            }
        }

        // 左旋:右子树高度过大
        if (getRightHeight()-getLeftHeight()>1){
            // RR:右子树的右子树上插入节点导致不平衡
            if (right.getRightHeight()-right.getLeftHeight()>=1){
                leftRotate();
            }else if (right.getLeftHeight()-right.getRightHeight()>=1){ // RL:右子树的左子树上插入节点导致不平衡
                // 右子树进行右旋
                right.rightRotate();
                // 整棵树左旋
                leftRotate();
            }
        }else if (getLeftHeight()-getRightHeight()>1){ // 右旋:左子树高度过大
            // LL:左子树的左子树上插入节点导致不平衡
            if (left.getLeftHeight()-left.getRightHeight()>=1){
                rightRotate();
            }else if (left.getRightHeight()-left.getLeftHeight()>=1){ // LR:右左子树的右子树上插入节点导致不平衡
                // 左子树进行左旋
                left.leftRotate();
                // 整棵树右旋
                rightRotate();
            }
        }
    }

    /**
     * 左旋
     */
    private void leftRotate() {
        // 1.创建新节点,与当前根节点值一致
        TreeNode newNode = new TreeNode(val);
        // 2.新节点的左子树为root的左子树
        newNode.left=left;
        // 3. 新节点的右子树为root的右子树的左子树
        newNode.right=right.left;
        // 4.root的值替换为其右子节点的值
        val=right.val;
        // 5.root的右子树为右子树的右子树
        right=right.right;
        // 6.当前节点的左子树为新节点
        left=newNode;
    }

    /**
     * 右旋
     */
    private void rightRotate() {
        // 1.创建新节点,与当前根节点值一致
        TreeNode newNode = new TreeNode(val);
        // 2.新节点的右子树为root的右子树
        newNode.right=right;
        // 3. 新节点的左子树为root的左子树的右子树
        newNode.left=left.right;
        // 4.root的值替换为其左子节点的值
        val=left.val;
        // 5.root的左子树为左子树的左子树
        left=left.left;
        // 6.当前节点的右子树为新节点
        right=newNode;
    }

    /**
     * 中序遍历
     */
    public void inOrder(){
        if (left!=null){
            left.inOrder();
        }
        System.out.println("node:"+val);
        if (right!=null){
            right.inOrder();
        }
    }

    /**
     * 层序遍历
     */
    public void levelOrder() {
        Deque<TreeNode> queue=new ArrayDeque<>();
        queue.offer(this);

        while (!queue.isEmpty()){
            TreeNode cur = queue.poll();
            System.out.println("node:"+cur.val);

            if (cur.left!=null){
                queue.offer(cur.left);
            }
            if (cur.right!=null){
                queue.offer(cur.right);
            }
        }
    }
}

2. B树|B+树

  • 二叉树实现简单,但由于其可能拥有极深的高度,往往实用价值不高;
  • n叉树的提出解决了二叉树的高度问题,可以降低二叉树高度;
  • n叉树:一个节点可以拥有两个以上的子节点的树称为n叉树;
  • 典型的n叉树:红黑树、2-3树、2-3-4树、B树;
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述

2.1 2-3树

  • 本质仍为排序树,需满足左<根<右的特点;
  • 2-3树由2节点、3节点构成;
  • 三叉B树;

在这里插入图片描述
在这里插入图片描述

2.2 B树的插入和删除

插入:

  • 通过B树关键字大小关系找到插入最底端位置,并进行放置;
  • 如果此处节点关键字数量超过最大关键字数量限制,则将本节点从中间位置一分为二,中间位置的元素插入父节点;
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

删除:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

资料来源:1)尚硅谷;2)王道考研

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NorthSmile

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值