浅谈树旋转

一些 update

update 2021/1/2:加入代码解释。

update 2021/1/13:发现『2.3 左旋』图片有重大失误,现在已经更正,对各位读者带来的不便深表歉意。

1.概述

树旋转,是 AVL 树和 Splay 等平衡树控制平衡的一种办法,同时也在别的领域有着重要的应用。

那么什么是树旋转呢?又有什么类型呢?

2.旋转

2.1 总览

比如下面这两棵树,上面的树对 0 号节点右旋后成为下面的树,下面的树对 1 号节点左旋后成为上面的树。

在这里插入图片描述

在这里插入图片描述

那么怎么做树旋转呢?这里给大家一句口诀(也是我从一些算法视频上学到的,并非原创):左旋拎右左挂右,右旋拎左右挂左。

什么意思呢?别急,等我细细道来。

2.2 右旋

首先我们看看右旋操作。

右旋拎左右挂左,那么第一步:拎左。

这是一开始的树:

在这里插入图片描述

那么我们对 0 号节点右旋,首先“拎左”:将左子树拎起来。

在这里插入图片描述

从上可以看到,在“拎左”之后 1 号节点现在是 0 号节点的父亲。

然后要“右挂左”:将拎起来的节点的右子树挂到需要旋转的节点的左子树上,在图中就是将 2 号节点挂到 0 号节点的左子树下,就是这样:

在这里插入图片描述

然后把树弄好看一点,就变成了这样:

在这里插入图片描述

那么现在你也应该猜到要怎么左旋了。

2.3 左旋

我们对上图的 1 号节点左旋。

左旋拎右左挂右。

首先“拎右”:我们将 1 号节点的右子树拎起来,像这样:

在这里插入图片描述

然后“左挂右”:将被拎起来的节点的左子树挂到需要旋转的节点的右子树上,也就是将 2 号节点挂到 1 号节点上,就是这样:

在这里插入图片描述

最后把树弄好看一点,就变成了这样:

在这里插入图片描述

所以这就是树旋转。

3.代码

代码(作者从 AVL 树上复制过来的):

void lrotate(int &now)//左旋
{
	int r = tree[now].r;//注意临时保存
	tree[now].r = tree[r].l;//左挂右
	tree[r].l = now;//拎右
	now = r;//拎右
	update(tree[now].l), update(now);//注意顺序
}

void rrotate(int &now)//右旋
{
	int l = tree[now].l;//注意临时保存
	tree[now].l = tree[l].r;//右挂左
	tree[l].r = now;//拎左
	now = l;//拎左
	update(tree[now].r), update(now);//注意顺序
}
posted @ 2022-04-14 20:35  Plozia  阅读(198)  评论(0编辑  收藏  举报