【Java】平衡二叉树旋转机制

当我们当树中添加节点的时候,它其实是通过旋转机制来保证树的平衡的。

旋转机制分为两种:左旋和右旋。

触发机制:当添加一个节点之后,该树不再是一颗平衡二叉树


一、左旋

1)情况1

如下图,添加 12 节点可以发现树失去了平衡。

image-20240427080806421

一旦失去平衡,就会触发旋转机制。

左旋:往左旋转,右旋:往右旋转,旋转的目的就是让这棵树保持平衡。

有的同学会想:右边的节点多,左边的节点少,那肯定是左旋。

答案是对的,但是推导过程是错的。

我们在旋转的时候首先需要确定支点:从添加的节点开始,不断的往父节点找第一个不平衡的节点。将遇到的第一个不平衡的点当做支点进行旋转。再以支点为基准再去判断是左旋还是右旋。

因此我们第一步需要先找支点,从添加的节点 12 网上找,它的父节点是 11,由于 11 是满足平衡二叉树要求的,因此我们需要往上找 10 节点,此时就发现了,10 节点已经不满足平衡二叉树要求了。

因此现在是以 10 为支点,并且 10 的右边比左边多,此时才断定进行左旋。

步骤:

  • 首先找到不平衡的点,以不平衡的点作为支点进行旋转
  • 把支点左旋降级,变成左子节点
  • 晋升原来的右子节点

这里的不平衡的点就是支点 10,此时就将支点 10 左旋降级,它原本的右子节点需要晋升,连带着 12 也要一起跑到上面。

image-20240427081632089

2)情况2

如下图添加 12节点 后就破坏平衡了

image-20240427082552990

首先我们需要找到支点:从添加的节点开始,不断的往父节点找第一个不平衡的节点。

一直网上找,可以发现 7节点 是支点。

旋转步骤

  • 首先找到不平衡的点,以不平衡的点作为支点进行旋转
  • 将根节点的右侧往左拉
  • 原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点

在旋转的时候,我们先当 9节点 不存在,此时就是按照刚刚的方式进行旋转,旋转完毕后再来看 9节点

9 原来是 10 的左子节点,此时 9 节点需要给已经降级的 7 节点的右子节点。

image-20240427084150669


3)经典GIF动画

我们再来看一张风靡各大数据结构网站上的经典图。

根节点的右侧 指的就是红圈圈出来的,此时可以想象是有人要把这一块往上拉。

image-20240427084527431

拉上去后,S 就需要变成新的根节点,原来的根节点 E 就需要降级为根节点的左子节点。

然后再将 S 的左子节点(即蓝色指向的地方),当做是 E 的右子节点。

image-20240427084824743

来看一下动态图,可以发现 S 这个整体被拉上去了。

frd1p-o0qox

二、右旋

1)情况1

右旋跟左旋就是反过来的。

如下图,添加 节点1 后破坏平衡了。

image-20240427085249511

既然平衡被破坏,就需要旋转了,第一步依旧是找支点,从添加的节点 1 开始往父节点寻找,找第一个不平衡的节点,将第一个不平衡的节点作为支点来进行旋转。

因此就是能找 4节点 支点,此时就需要将 4节点 当做支点进行右旋。

旋转步骤:

  • 以不平衡的点作为支点
  • 把支点左旋降级,变成右子节点
  • 晋升原来的左子节点
image-20240427090549279

2)情况2

如下图,在刚刚的树上添加了 1节点,此时就破坏平衡了,因此此时需要通过右旋保证这棵树再次平衡。

image-20240427090704444

此时的支点应该就是 7节点,此时我们就需要以 7节点 作为支点来进行右旋。

步骤:

  • 以不平衡的点作为支点
  • 将根节点的左侧往右拉
  • 原先的左子节点变成新的父节点,并把多余的右子节点出让,给已经降级的根节点当左子节点

image-20240427091619791


3)经典GIF动画

根节点的左侧就是圈起来的这一块,你可以想象有人要把这块往上拉,拉上去后,这里的 E 就变成了新的根节点。

image-20240427091822372

而原来的根节点 S 就会降级,变成新的根节点的右子节点,那么 E 原来的右子节点就需要给 S 当做是它的左子节点。

02z0n-jo34s

在刚刚我们学习的左旋跟右旋,仅仅只是保持平衡的手段。

那么什么时候会触发左旋,什么时候会触发右旋呢?


三、需要旋转的四种情况

这四种情况分别为:左左、左右、右右、右左

1)左左

左左:当根节点左子树的左子树有节点插入,导致二叉树不平衡。

例如在下图的平衡二叉树中添加 节点1 / 节点3,此时就是在根节点的左子树的左子树上进行添加。

根节点的左子树就是蓝色虚线的地方,即 4节点4节点 的左子树就是绿色虚线的地方。

添加后,一共会有两种情况,这两种情况其实是一样的。

image-20240427093553280

添加后,这棵树就已经不平衡了,此时我们就需要从添加的节点开始,不断的往上找不平衡的点作为支点,然后再进行旋转。

此时就会找到 7节点 是支点,因此此时我们需要以7节点 作为支点进行右旋。

在这种情况下,不管是添加节点1还是节点3,都只需要做一次右旋就行了。

因此如果是因为左左导致不平衡,那么一次右旋就能搞定。

frd1p-o0qox

2)左右

左右:当根节点左子树的右子树有节点插入,导致二叉树不平衡。

这种情况就比较复杂了,不是一次旋转就能搞定的。

如下图,我需要在根节点左子树的右子树添加节点。

根节点的左子树就是下面蓝色虚线部分,左子树的右子树,就是绿色虚线的这部分。

在此基础上添加一个节点,那我们如何去旋转呢?

image-20240427094935615

有的人说简单,右旋一次不就行了吗?

我们先来找支点,可以发现 7 是支点,因此此时需要 根节点7 作为支点来进行右旋。

image-20240427095438666

旋转完毕后发现,这棵树还没平衡。

因此左右的情况下,一次右旋是不行的。

不着急,我们先将这棵树归位,此时就需要分成两步了

  • 将紫色部分进行局部左旋,将左右的情况变成左左
  • 此时再进行一次右旋就行了

image-20240427095909598


3)右右

右右跟刚刚的左左其实是反过来的。

右右:当根节点的右子树的右子树有节点插入,导致二叉树不平衡。

例如下图,蓝色虚线的地方为根节点的右子树,即 10节点

10节点 的右子树为 11节点,即绿色虚线部分。

此时将 12节点 添加在该处,此时就是:在根节点的右子树的右子树上添加了节点,此时平衡就被破坏了。

image-20240427100330077

因此我们需要进行左旋让这棵树保持平衡。

以根节点 7 作为支点进行旋转,因此在右右的情况下,一次左旋就能搞定了。

image-20240427100646969


4)右左

右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡。

例如下图,根节点的右子树就是蓝色虚线这块,右子树的左子树就是绿色虚线这块。

当添加节点8后,树就不平衡了。

image-20240427100931753

此时就需要进行旋转来平衡二叉树。

但是一次左旋真的能搞定吗?

image-20240427101205549

可以发现,旋转后树还是不平衡的,因此跟刚刚一样,仅仅一次左旋还是不够的。

跟左右一样,也需要进行两步。

将下方局部位置进行右旋,右旋后跟刚刚的右右就一模一样了,然后再进行整体的左旋,此时就搞定了。

image-20240427101615448


四、总结

1)回顾

首先是二叉树,在普通的二叉树中,数据是没有任何规律的,查询效率会比较低,为了解决这个问题,所以有了二叉搜索树。

在添加节点的时候会遵守一个规则:小的存左边,大的存右边,一样的不存。因此它的数据就有规律了,那么在查询起来的时候效率也比较高。

image-20240427102019194

但是它有自己的弊端,它容易出现长短腿的现象,一旦出现长短腿,那么就跟链表差不多了,而且还是单向链表,同样会影响效率。

所以为了解决这个问题,就有了平衡二叉树。在平衡二叉树中,任意节点左右子树高度差不能超过1,因此它的查询效率要更高。

image-20240427102115426 ----

2)在平衡二叉树中,如何添加节点?

平衡二叉树本身也是一颗二叉查找树,只不过是在二叉查找树的基础上保证了树的平衡而已。

因此它在添加节点的时候也会遵守:小的存左边,大的存右边,一样的不存。


3)在平衡二叉树中,如何查找单个节点?

在树这种数据结构中,查找元素一定是从根节点开始查找的。


4)为什么要旋转?

普通的二叉树跟二叉查找树是不需要旋转的,到目前为止,只有平衡二叉树才需要旋转。

旋转的目的就是:当我们添加一个节点,导致这棵树不平衡了,此时就需要利用旋转让这棵树重新平衡。


5)旋转的触发时机?

当成功添加一个节点后,破坏了这棵树的平衡,就需要进行旋转。

但是如果没有破坏平衡,是不需要进行旋转的。


6)左左是什么意思?如何旋转?

左左:当根节点左子树的左子树有节点插入,导致二叉树不平衡。

一次右旋就ok。


7)左右是什么意思?如何旋转?

左右:当根节点左子树的右子树有节点插入,导致二叉树不平衡。

需要先局部左旋,然后再整体右旋。


8)右右是什么意思?如何旋转?

右右:当根节点的右子树的右子树有节点插入,导致二叉树不平衡。

一次左旋就ok。


9)右左是什么意思?如何旋转?

右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡。

需要先局部右旋,然后再整体左旋。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值