自平衡二叉树(Self-balancing binary search tree)

排序二叉树有以下缺点:

同样的关键字集合有可能导致不同的树结构索引,如下图的右图所示,此时他的搜索性能已经是线性的了,为了解决这种"树一边倒的现象",自平衡二叉树就被提出来了。平衡二叉树的目的是为了减少二叉查找树层次,提高查找速度。

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

平衡二叉树

定义:平衡二叉树或为空树,又被称为AVL树(有别于AVL算法)或为如下性质的二叉排序树:
(1)左右子树深度之差的绝对值不超过1;
(2)左右子树仍然为平衡二叉树.
平衡二叉树必定是二叉搜索树,反之则不一定。
平衡二叉树的常用实现方法:AA树、AVL树、红黑树、树堆Treap、伸展树等AVL 树是高度平衡的,频繁的插入和删除,会引起频繁的reblance,导致效率下降
红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转。

平衡因子(平衡度)

平衡因子=左子树高度-右子树高度

当平衡因子为1,-1,0时,当前的树处于平衡状态,当平衡因子为2,-2时,当前树处于不平衡状态,需要进行自平衡
在这里插入图片描述

如何进行自平衡

  • 找平衡因子=2/-2
  • 找插入新结点后失去平衡的最小子树
    该子树要求:
    1.距离插入结点最近
    2.平衡因子绝对值为1的结点作为根
  • 平衡调整(有4种情况如下)
    在这里插入图片描述
    左旋和右旋?
    总结了一句口诀(主要用于写代码):
左旋:其右子(若有)给其父结点的左结点
右旋:其左子(若有)给其父结点的右结点        

如图演示:在这里插入图片描述

代码实现

叶点类:

class AVLTreeNode{
    public int data;
    public AVLTreeNode left;
    public AVLTreeNode right;
    public int height;
    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
    public AVLTreeNode getLeft() {
        return left;
    }
    public void setLeft(AVLTreeNode left) {
        this.left = left;
    }
    public AVLTreeNode getRight() {
        return right;
    }
    public void setRight(AVLTreeNode right) {
        this.right = right;
    }
    public int getheight() {
        return height;
    }
    public void setheight(int height) {
        this.height = height;
    }
    public AVLTreeNode(int data){
        initiateNode(data,null,null,1);
    }
    public AVLTreeNode(int data,AVLTreeNode left,AVLTreeNode right,int height)
    {
        initiateNode(data,left,right,height);
    }
    public void initiateNode(int date,AVLTreeNode left,AVLTreeNode right,int height)
    {
        this.setData(date);
        this.left=left;
        this.right=right;
        this.height=height;
    }
    // 返回左子树的高度
    public int leftHeight() {
        if (left == null) {
            return 0;
        }
        return left.height();
    }
    // 返回右子树的高度
    public int rightHeight() {
        if (right == null) {
            return 0;
        }
        return right.height();
    }
    //递归返回以该结点为根结点的树的高度
    public int height() {
        //+1因为本身也占一层
        return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
    }
}

LL型旋转:
在这里插入图片描述

/*
     * LL型旋转;左左对应的情况(左单旋转)
     * 传入值:旋转前的根结点
     * 返回值:旋转后的根节点
     */
    private AVLTreeNode leftLeftRotation(AVLTreeNode root) {
        AVLTreeNode rootLeft=root.left;
        //右子结点给父结点的左结点
        root.left=rootLeft.right;
        //将原根结点作为rootLeft的右结点,让rootLeft成为新的根结点
        rootLeft.right=root;
        //重新计算高度
        root.height = root.height();
        rootLeft.height = rootLeft.height();
        return rootLeft;
    }

在这里插入图片描述

    private AVLTreeNode rightRightRotation(AVLTreeNode root) {
        AVLTreeNode rootRight=root.right;
        //左子结点给父结点的右结点
        root.right=rootRight.left;
        //将原根结点作为rootRight的左结点,让rootRight成为新的根结点
        rootRight.left=root;
        //重计算高度
        root.height = root.height();
        rootRight.height=rootRight.height();
        return rootRight;
    }

LR旋转:需要经过两次旋转(右旋后左旋)才能让AVL树恢复平衡
在这里插入图片描述

 private AVLTreeNode leftRightRotation(AVLTreeNode root) {
        //先右旋再左旋
        root.left = rightRightRotation(root.left);
        return leftLeftRotation(root);
    }

在这里插入图片描述

  private AVLTreeNode rightLeftRotation(AVLTreeNode root) {
        root.right = leftLeftRotation(root.right);
        return rightRightRotation(root);
    }
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值