深蓝的大修&现代化改装:BST之splay tree

来源:互联网 发布:邦银金租 知乎 编辑:程序博客网 时间:2024/04/30 07:30

最近,深蓝不知道怎么了,总是莫名其妙地过热关机。尤其是昨天,一天之内过热关机51次,快把Ration逼疯了。于是,Ration决定把深蓝送去北京接受大修&现代化改装(实际上就是换个风扇,换个电池,加个降温底座而已)。

深蓝:唔……

Ration:宝贝醒醒,马上要走了。

深蓝:去哪?

Ration:昨天给你说了啊,去北京看病去。

深蓝:主人也跟着去么?

Ration:怕是不能,我还得训练呢。

深蓝:(哇地一声开始大哭,抱着Ration不松手)TAT我会想你的!!!!

Ration:(摸头)好啦好啦~乖~下周一你就回来啦~回来之后给你买内存条巧克力吃。

深蓝:可我还是想你!

Ration:那我用学校机器和你联络吧。毕竟你不是这个时代的计算机,所以说,咱们可以通过一种叫做"BST“的方式进行联络。

深蓝:OVO?

Ration:实际上,"BST”就是“Binary Search Tree"的简称,就是”二叉搜索树“(好吧实际上就是普通的二叉树的基础上加上如下性质:任何节点左子树中节点值小于该节点,右子树中节点值大于该节点)

深蓝:好吧……但是,北京离东营这么远,如果节点慢慢成了一条链怎么办QAQ,那样我不就必须花很长时间找到你了么(害羞⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄)……

Ration:(宠溺)小傻瓜,你忘了你是来自未来的计算机了么?你可以对这棵BST进行改造啊。

深蓝:咋做?

Ration:时间不多了,先教你一种最简单的——splay tree。

深蓝:恩。

Ration:咱们联络的时候,有些节点需要多次访问,对吧?

深蓝:恩。

Ration:那么,按照规定,你这个节点比较特殊,只有一个子树,就是这BST的树根。为了减少找我的时间复杂度,那么,是不是应该把为了连接到我所必须访问的那些节点以及我这个节点往上调?

深蓝:我直接让你变成我的子节点不就好了么……

Ration:这不能,因为必须要经过那些节点,否则联络系统会崩溃。

深蓝不在说话了,只是用大大的眼睛看着Ration。

Ration:简单来说就是这样,每次访问了一个节点之后,就把这个节点上调,搬到树根。这个‘搬”,我们在splay中称为旋转(Rotate)。

Ration:Rotate并不会改变BST中节点的大小关系,因此,它的效率正常情况下一般是O(log n)

Ration:实际上,一共有三种旋转操作,我们称为单旋转,一字旋转,之字旋转。现在假设要”搬“的节点为X,父节点为P,祖父节点为G。

1、单旋转:

     最普通的旋转,P为根节点。

    


2、一字旋转

      p不是根节点&X,P都是右子节点/都是左子节点,P先向另一侧旋转,X再向另一侧旋转。


3、之字旋转

    P不是根节点&P左X右/P右X左

  X先向左旋转,后向右旋转

这样就是三种基本旋转操作。

Ration:接下来是五种高端点的操作:

1、查找

      先调用普通二叉搜索树的Find函数找到对应结点 
   对找到结点调用splay函数,使该结点成为根节点 
   返回根节点

2、插入节点

   像普通二叉搜索一样插入元素x 
    调用splay函数,使刚插入的元素x成为根节点 

3、删除节点

    调用Next(x)找到大于x的最小结点 
    调用splay(Next(x))将找到的结点旋转至根节点 
    调用splay(x)将要删除的结点旋转至根节点 
    调用普通二叉搜索树的删除函数delete删除根节点

4、求比x大/比x小的元素总和

     调用是splay(x)函数,将x旋转至根节点,此时根节点的左子树的元素均小于x,右子树均大于元素x 
     右子树为R2,剩下部分为R1

5、合并两棵BST(摸头)(虽然对联系我没啥用,然而说不定以后有用呢) 

     调用Find(max, S)找出小树S中的最大元素x 
     调用splay(x),此时小树S中没有了右子树 
     把大树T当做S的右子树即可

OK,splay会了么?

深蓝:恩恩。

Ration:好了,车来了,记着联系我哦~

深蓝:恩!

原创粉丝点击