数据结构--简单理解平衡搜索树的旋转

主要是开始感觉这个旋转太不像我们平时理解的关于一个点的旋转了。第一次看也很模糊,到第二次看,发现其实就是保持大小的一个旋转。

首先讲一点点关于二叉搜索树的定义:
每个节点p存储一个键值对(k, v)的二叉树T,使得:

  • 存储在p的左子树的键都小于k
  • 存储在p的右子树的键都大于k

其实旋转就是在以上基础上形成的。我们知道一个键的左子树一定会小于k,也就是说,键k大于左子树的键。利用这两者的等价性,就可以开始构造我们的旋转。比如说x是y的左子树,即x的键小于y,那么我们就可以进行旋转保持等价关系,将y作为x的右子树,这样的一个过程就叫做旋转。
其实从数学上来讲就是
x < y ⇔ y > x \begin{aligned} x < y \Leftrightarrow y > x \end{aligned} x<yy>x
对应到搜索二叉树上就是
x 是 y 的 左 子 树 ⇔ y 可 以 作 为 x 的 右 子 树 x 是y的左子树 \Leftrightarrow y可以作为x的右子树 xyyx
以上只是针对两个节点之间的旋转,但是事实上,这两个节点下面一般也还有一些子树。在旋转的同时我们还需要对对这些子树旋转,以保持搜索二叉树的属性。

比如说x< y,初始的时候,x是y的左子节点,开始一个二叉树,y还有一个右子树,x有一个左子树和右子树。x的左子树是小于x的,x的右子树是大于x的。同时又因为这是中序遍历,需要将一个节点的左子树遍历完之后再开始遍历这个左子树所属的根,也就是这里的y节点,所以说x的右子树是小于y的。

在对x旋转之后,我们就将x的右子树作为y的左子树(之前讲过,x的右子树上的只是小于y的)。在经过旋转之后,我们得到的二叉树依然是一个搜索二叉树。

图1 x 旋转之前
图2 x旋转之后
原始的图形是这样的,在我们旋转了之后,就变成了右图。 从右边向左边旋转也是一样的操作。

一般经常用的还有:三个节点之间旋转,一般有四种情况:
在这里插入图片描述
基本的情况如图所示:
理解a)和b)两种情况之后,就可以先将c)和d)中的先转换成a)和b)中的,再按照a)和b)的旋转,这就是我们旋转所要得到的最终结果。
我贴一下书本上的代码:

# 重新构建父子关系,有一个控制是作为左节点还是右节点的参数make_left_child
def _relink(self, parent, child, make_left_child):
	if make_left_child:
		parent._left = child
	else:
		parent._right = child
	if child is not None:
		child._parent = parent

# 进行旋转	
def _rotate(self, p):
	x = p._node
	y = x._parent
	z = y._parent
	# 其那半部分是对有两个节点还是三个节点的处理
	if z is None:
		# 是两个节点,则就将最底层的节点作为根节点
		self._root = x
		x._parent = None
	else:
		# 否则,三个节点,就连接x与z之间的父子关系
		# x是z的左节点或者说是右节点取决于y是z的左节点还是右节点
		self._relink(z, x, y == z._left)
	
	# 这是两个节点的情况,根据上面的图一图二的操作来进行旋转
	if x == y._left:
		self._relink(y, x._right, True)
		self._relink(x, y, False)
	else:
		self._relink(y, x._left, False)
		self._relink(x, y, True)

# 无论是三个节点还是两个节点,一起处理,节点重建
def _restructure(self, x):
	y = self._parent(x)
	z = self._parent(y)
	# 是上图的a)或者b)的情况
	# 这里是考虑两个节点的情形_rotate的第一种情况
	# 返回按照(哪个节点旋转),这个节点
	if (x == y._left) == (y == z._left):
		self.rotate(y)
		return y
	# 对应上图c)和d)的情形
	# 首先对底层节点x旋转一次,这里是三个节点的情况
	# 再对中间节点x旋转一次,将x作为根节点
	else:
		self._rotate(x)
		self._rotate(x)
		return x

后记:关于何时需要旋转以及怎么旋转,看书发现旋转都是从底层下面的节点开始旋转。每次旋转都是依照着这个准则:总是将较低层的节点旋转到较高的节点停止(将深度比较高的节点,旋转到深度比较低的节点,或者说是将高度比较低的节点旋转到高度比较高的节点)。不清楚整体是否是这样,但是在我看伸展树的时候是这样的一个规律。

不过还不完全确定,待以后学习通了自己再来解答这个问题。

参考:《数据结构与算法 Python语言实现》迈克尔·T.古德里奇
P313-P316

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值