Tree | 伸展树

本文目录

一、伸展树的基本概念

二、Splay —— 伸展操作的原理 

1、P 是根节点

2、P 不是根节点

Z字型旋转(Zig-zag)

一字型旋转(Zig-zig)—— 左

一字型旋转(Zig-zig)—— 右

三、伸展操作的实现

四、利用伸展树实现其他操作

1、Find(x,S)

2、Insert(x,S)

3、Delete(x,S)

4、Join(S1,S2)

5、Split(x,S)

 


本文将要介绍的伸展树(Splay Tree),是对二叉查找树的一种改进。

虽然它并不能保证树的外观结构上一直是“平衡”的,但对于伸展树的一系列操作,我们可以证明其每一步操作的平摊复杂度都是O(log n)。所以从性能上说,伸展树也是一种平衡的二叉查找树。而在各种树状数据结构中,伸展树的空间要求与编程复杂度也都是很优秀的。
 

一、伸展树的基本概念

伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性 —— 对于每一个节点x都满足:该节点左子树中的每一个元素都小于x,而其右子树中的每一个元素都大于x。

比二叉查找树更丰富的是:伸展树可以自我调整 —— 展开(splay)操作:可以将某一元素x所在节点调整到根部。 


为了方便理解,下面对任意一非根节点x给出以下定义:

父亲节点P:x的父节点

祖父节点G:P的父节点

二、Splay —— 伸展操作的原理 

伸展操作:在保持伸展树有序性的前提下,通过一系列旋转操作将伸展树中的元素x调整至树的根部

对于旋转的操作,如果没有接触过的话,建议先看看AVL树的旋转(传送门->秒懂AVL树

且以下旋转操作不要与AVL树旋转混淆,有所异同。


1、P 是根节点

直接将x与p单即可旋转,如果x是P的左孩子就进行左旋转,反之进行右旋转。

和AVL树的单旋转一样

2、P 不是根节点

Z字型旋转(Zig-zag)

一般模型如下图:

适用情况:x、P、G路径构成折线。 

注意理解:上面只是显示了从G开始的树,并不代表G就是根节点。从一般情况下理解:图中的树也许只是某一棵树的一部分子树。

具体步骤:与AVL树的单旋转还是有差别的 

       🔺 将X的右子树挂在G的左子树上(此时P与G断开了)

       🔺 将X的左子树挂在P的右子树上(此时X与P断开了)

       🔺 将G挂在X的右子树上

       🔺 将P挂在X的左子树上


一字型旋转(Zig-zig)—— 左

适用情况:x、P、G路径是直线段,无折点。

注意理解:上面只是显示了从G开始的树,并不代表G就是根节点。从一般情况下理解:图中的树也许只是某一棵树的一部分子树。 

具体步骤:与AVL树的单旋转还是有差别的 

       🔺 将P的右子树挂在G的左子树上(此时P与G断开了)

       🔺 将G挂在P的右子树上

       🔺 将X的右子树挂在P的左子树上(此时X与P断开了)

       🔺 将P挂在X的右子树上

一字型旋转(Zig-zig)—— 右

和左的情况差不多,先省去不写了。


下面来个实际的例子理解一波:

将这棵树在K1处伸展(将K1移动到根节点)

▲先经过Z字型旋转:

▲再经过一字型旋转: 


可以发现:其实伸展操作不仅仅将节点移动到了树的根部,其也将旋转路径上大多数节点的深度减半,让树更加均衡了。

三、伸展操作的实现

Splay(x,S):将x转移到伸展树S的根节点上

代码实现如下:

 

四、利用伸展树实现其他操作

利用Splay操作,我们可以在伸展树上进行如下运算:

1、Find(x,S)

判断元素x是否在伸展树S表示的有序集中。
首先,与在二叉查找树中的查找操作一样,在伸展树中查找元素x。如果x在树中,则再执行Splay(x,S)调整伸展树。

2、Insert(x,S)

将元素x插入伸展树S表示的有序集中。
首先,也与处理普通的二叉查找树一样,将x 插入到伸展树S中的相应位置上,再执行Splay(x,S)。

3、Delete(x,S)

将元素x从伸展树S所表示的有序集中删除。
首先,用在二叉查找树中查找元素的方法找到x的位置。如果x没有孩子或只有一个孩子,那么直接将x删去,并通过Splay操作,将x节点的父节点调到伸展树的根节点处。否则,则向下查找x的后继y,用y替代x的位置,最后执行Splay(y,S),将y调整为伸展树的根。

4、Join(S1,S2)

将两个伸展树S1与S2合并成为一个伸展树。其中S1的所有元素都小于S2的所有元素。首先,我们找到伸展树S1 中最大的一个元素x,再通过Splay(x,S1)将x 调整到伸展树S1 的根。然后再将S2 作为x 节点的右子树。这样,就得到了新的伸展树S。

5、Split(x,S)

以x 为界,将伸展树S 分离为两棵伸展树S1 和S2,其中S1中所有元素都小于x,S2中的所有元素都大于x。首先执行Find(x,S),将元素x 调整为伸展树的根节点,则x 的左子树就是S1,而右子树为S2。
 

 



End

欢迎关注个人公众号“鸡翅编程”,这里是认真且乖巧的码农一枚,旨在用心写好每一篇文章,平常会把笔记汇总成推送更新~

发布了22 篇原创文章 · 获赞 16 · 访问量 1664
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 1024 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览