• [转]Splay Tree


      转自:http://blog.sina.com.cn/s/blog_7c4c33190100sg9r.html

    Splay Tree(又叫伸展树)本质上也是一棵二叉查找树。它不是严格平衡的,但通过一种伸展(splay)操作可以使它一次操作的时间均摊复杂度为O(logN)。详细时间复杂度证明请参考集训队论文。这里,我只说说伸展树的实际操作。

        和其他二叉查找树一样,Splay Tree支持查找询问、修改、加入、删除等操作,但又有所不同。

    对于询问,每次找到目标值后,把目标位置伸展到根。

        对于修改,与询问类似。

        对于加入,如果是一个节点加入,则与上列相似。若是插入一个区间(一棵子树),可以把要插入地方的前一个节点伸展到根,把后一个节点伸展到根的右节点,这样就可以直接把那棵子树作为根节点的右节点的左子树了。

        删除的原理与加入相同,都是把要删除的区间弄成(就是把前一个点伸展到根,后面第一个节点伸展到根的右节点)根节点的右节点的左子树,然后直接拿掉就行了。

        (以上所有伸展操作指的都是splay操作)

        以上所有操作都涉及到一个splay操作,那splay操作是什么呢?了解Treap的应该都明白用来维护树平衡的左旋和右旋操作,splay操作就是一系列的左旋和右旋操作。

        为什么要进行splay操作呢?这样在询问后不是要用很多时间来splay?这样不是会增大时间的消耗吗?可是想想,如果多次询问一个很深的节点的话,每一次询问的复杂度都会接近N,这样二叉树就很容易超时。每一次都做splay后可以证明所有操作的均摊复杂度是O(logN),这样,就保持了二叉查找树的优美性。

        那splay操作如何实现呢?

        我们不妨设要伸展至根的节点为x,根为root,x的父亲是y,y的父亲是z。

        首先,它分单选和双旋两种基本操作。

        单选:当y是root的时候,直接用一个左旋或者右旋(Treap的操作,见附注)就可以把x伸展至根。

        双旋:这就要分两种情况讨论了。

            ①:x和y同为它们父亲的左儿子或右儿子时,先把y旋到z,再把x旋到y。(同样是用左旋和右旋操作)

            ②:x和y不同为它们父亲的左儿子或右儿子时,把x做两个单旋。(左右旋操作)

        为什么要有双旋的①操作呢?试想一下如果当前是一条链的话,在查询完最深的节点后,如果没有①的操作而只用N个单旋把节点单旋上去的话,splay操作后的树仍然是一条链,如图1-1至图1-5:

         

      但若是用双旋的话情况就不同了,如图2-1至2-5:

           

            

    在询问节点数很大的链时,双旋的优越性更明显。

    以上操作可以通过调用一个子程序splay(root,x)完成,表示把x节点伸展到根。很明显,如果我们把root改成x到根路径上面的任意一个节点,就可以把x节点伸展到x到根的路径上任一位置。

    附注:

    可以看出,左旋和右旋适用于一棵二叉树中的任意一个节点,并且在旋转之后的二叉树保证合法性。

    这里有一道Splay Tree的练手题,虽然它可以用时效性很高的树状数组做,也可以用线段树做,或者是其他的各种树做。。。但就当它只能用Splay Tree做好了。。。据说能过这题的Splay常数就不会太大。

    http://www.cnblogs.com/zhsl/p/3189912.html

  • 相关阅读:
    Android_项目文件结构目录分析
    WPF_MVVM 开发的几种模式讨论
    Blend_技巧篇_淡入淡出
    Blend_技巧篇_导入PSD文件制作ToggleButton (Z)
    Blend_界面快速入门(Z)
    Blend_软件系列简介(Z)
    Blend_ControlTemplate(Z)
    803. 区间合并
    P4017 最大食物链计数
    P1113 杂务
  • 原文地址:https://www.cnblogs.com/zhsl/p/3189901.html
Copyright © 2020-2023  润新知