2024年Go最新平衡二叉树(AVL树),原来如此!,2024年最新字节跳动架构师讲解Golang开发

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

}

public void remove(int val) { //删除对应的节点
    
}

public boolean contains(int val) { //查询是否有该值
    
}

}


## 二、插入操作


首先,平衡二叉树与搜索二叉树的差别在于:平衡二叉树,它自己可以自动调节整棵树的平衡,也叫自平衡机制。 所以在平衡二叉树里,有一个概念叫做`平衡因子`,意思就是: **对于每一个子树而言,它的左子树的高度 减去  右子树的高度  ,差值的绝对值不能超过1**;换句话说就是:两边高度相减的范围必须在[-1,1],这个区间呢,才能称为平衡。这也是我们为什么在TreeNode类里面加入了height这个变量的原因。


插入操作,我们只需掌握4种不同情况导致的不平衡。分别是 `LL型、RR型、LR型和RL型`。


* LL型

 ![image-20210822155739452](https://img-blog.csdnimg.cn/img_convert/ea6b1c5b6817da6d6cd2251c0b06a467.png)

 就如上面这幅图所示,当我们插入5节点后,计算平衡因子,我们就会发现,在12结点处的平衡因子超过了1,所以我们需要对12这个节点进行调整。正是因为2节点的插入,从而导致了12节点的不平衡,而5节点在12节点的左子树(8节点)的左子树(5节点)。所以这种情况就叫LL型。我们稍微将上面的图再“装饰”一下,将它们各自的子节点都显示出来,如下图:(注:T1~T4,在实际的情况中可能没有,此时是为了让大家更好理解如何去进行旋转操作,才加上的)

 ![image-20210822161009667](https://img-blog.csdnimg.cn/img_convert/0884b90b82b4ed1f0f534661893b32a0.png)

 **LL型动图**

 ![0822-LL型右旋转](https://img-blog.csdnimg.cn/img_convert/333a8929175e142b9fda078edd2b083f.gif)

 对于LL型,我们需要进行右旋转操作,同学们根据动图,自行在纸上画一下是如何进行连接的,就能更好的理解其中的关系。代码图如下:

 ![image-20210822163324065](https://img-blog.csdnimg.cn/img_convert/e93bb6138ce630d309b34e4fafd645f7.png)

 最后,我们还要再说一下,旋转之后,只有两个节点的高度是需要更改的,就是root和tmp这两个节点的高度,等于它左右子树的高度,再加上自己本身的高度值1,就是旋转之后,这个节点的新高度了。切记:必须先计算root的高度之后,才能计算tmp的高度,因为root是tmp的右子树,tmp的高度是依赖于root的高度值。
* RR型

 讲完了LL型,RR型,也就简单了许多,RR型和LL型是差不多的。只是二者互为镜像而已。我们就直接看动图吧!

 **RR型动图**![0822-RR型左旋转](https://img-blog.csdnimg.cn/img_convert/bc95d1c58fadfe48897852473dd9d9fa.gif)

 计算高度的节点还是root和tmp这两个节点,还是先计算root的高度,再计算tmp的高度。代码图如下:

 ![image-20210822170313662](https://img-blog.csdnimg.cn/img_convert/854c9cddc89279c48b87fd5b827161c1.png)
* LR型

 讲完了LL型和RR型,接来了的LR和RL型,就非常简单,因为LR和RL,根本不需要重新再写新的方法,我们只需要旋转两次,就是LR或者RL的操作,多的不说,我们以图为切入点,展开来讲;

 ![image-20210822171751640](https://img-blog.csdnimg.cn/img_convert/ad8d213a571b853240c694a45445986c.png)

 上图就是LR型的情况,当我们尝试着上面的LL型和RR型,发现是解决不了问题的。我们只有想办法让LR型转化成LL型,问题就迎刃而解了。问题在于怎么转化? 来,我们看下图:

 ![image-20210822172600448](https://img-blog.csdnimg.cn/img_convert/51818bd61c57ead59ab0041ff2936d4e.png)

 我们可以发现,我们只需将8节点先向左旋转一下,就能得到LL型的状态。得到LL型后,问题就回到了LL型上,那我们再整体向右旋转一次,就能达到平衡的效果。我们以动图来演示一下:

 **LR型动图**  
 ![请添加图片描述](https://img-blog.csdnimg.cn/15bcc34717f74bf3ae480c9108ea2f84.gif)
* RL型

 相应的RL型,跟LR型也是差不多,就是镜像而已。`LR是先左旋转再右旋转,而RL是先有旋转再左旋转`。我们还是以图来展开说明吧!

 ![image-20210822180335810](https://img-blog.csdnimg.cn/img_convert/3ce3fa124c08494763041f8b17aaab7a.png)

 旋转过程如下:

 ![image-20210822181135642](https://img-blog.csdnimg.cn/img_convert/3e24325774ee0ea23d66dd5d091d43bf.png)


整体的代码演示,我先以图片的形式,将框架分出来,看着更为直观一点,更容易理解一点。


![image-20210822182254316](https://img-blog.csdnimg.cn/img_convert/116ad905313ad91fb5de3260872f1f78.png)



public void add(int val) {
root = add(root, val);
}

private TreeNode add(TreeNode node, int val) {
if (node == null) {
return new TreeNode(val);
}

if (val < node.val) {
    node.left = add(node.left, val);
} else { //大于等于的情况,还是需要新建节点
    node.right = add(node.right, val);
}

//计算当前节点的高度
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1; //取左右两边的最大值,再加1

//计算平衡因子
int balanceFactor = getBalanceFactor(node);
if (Math.abs(balanceFactor) > 1) {
    //LL型,做右旋转处理
    if (balanceFactor > 1 && getBalanceFactor(node.left) >= 0) {
        return R\_Rotate(node); //直接将新的根结点返回即可
    }

    //RR型,做左旋转处理
    if (balanceFactor < -1 && getBalanceFactor(node.right) <= 0) {
        return L\_Rotate(node); //新的根节点,直接返回
    }

    //LR型,先对左子树进行左旋转,然后再对根节点进行右旋转
    if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) {
        node.left = L\_Rotate(node.left); //先进行左旋转,变成LL型
        return R\_Rotate(node); //再进行右旋转
    }

    //RL型,先对右子树进行右旋转,然后再对根节点进行左旋转
    node.right = R\_Rotate(node.right);
    return L\_Rotate(node);
}
return node;

}

//计算平衡因子
private int getBalanceFactor(TreeNode node) {
if (node == null) {
return 0;
}
return getHeight(node.left) - getHeight(node.right);
}
//计算节点的高度
private int getHeight(TreeNode node) {
if (node == null) {
return 0;
}
return node.height;
}


这样的话,平衡二叉树的插入操作,我们就讲完了。接下来,我们来看看删除操作。


## 三、删除操作


删除和插入是一样的,我们只是在搜索二叉树的删除操作上,做一些改动,就能实现平衡二叉树的删除操作。


分析:整棵树原本是已经平衡了,是因为我们需要删除一个节点,从而导致整棵树产生不平衡。所以们只需要从删除的节点处,向上一直遍历,一直向上回溯,然后计算回溯到的节点,重新计算高度,重新计算平衡因子即可。操作完全就是add方法的一样,直接拷下来即可。下图是搜索二叉树的删除操作:


![image-20210823092258641](https://img-blog.csdnimg.cn/img_convert/69994903908b1262ba093c2eaf2f5b06.png)


平衡二叉树的删除,简直就是一模一样。我们可以发现,在上面图中删除之后,就是直接返回了node节点,。


**而平衡二叉树删除,就是不要先返回node节点,先对node节点进行计算height,并且计算平衡因子,如果平衡因子超过1了,就调整即可。如果平衡因子没超过1,此时 返回node节点就行**。


平衡二叉树删除操作代码大致框架如下:


![image-20210823093555221](https://img-blog.csdnimg.cn/img_convert/74696b89d8de5942a99f3060ff52cae4.png)



public void remove(int val) {
root = remove(root, val); //方法重载
}

private TreeNode remove(TreeNode node, int val) {
if (node == null) {
return null;
}

if (val < node.val) { //小于
    node.left = remove(node.left, val);
} else if (val > node.val) { //大于
    node.right = remove(node.right, val);	
} else if (node.left != null && node.right != null) { //相等的情况,并且有左右两个孩子
    
    TreeNode minNode = getMinNode(node.right); //返回的是,node的右子树的最小节点
    minNode.right = remove(node.right, minNode.val); //以这个最小节点作为新的node返回,并删除右子树上的minNode
    minNode.left = node.left;
    
    node =  minNode; //这里先将minNode保存到node里面
    
} else { //相等的情况,只有一个孩子节点,或者是没有节点情况
    node = node.left != null? node.left : node.right;
}


//对node节点进行判断,并计算height和平衡因子。

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值