- 浏览: 512461 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jkxydp:
算法运行的结果根本就不对。
BM算法. -
soarwindzhang:
感谢博主的分享,我今天看了您的UFSET非递归的路径压缩时感觉 ...
并查集 -
zhangning290:
楼主好像只考虑了坏字符规则,。没有考虑好后缀
BM算法. -
lsm0622:
文字描述有错误 误导新学者
求有向图的强连通分量(scc):Tarjan算法 -
knightchen:
博主,你太强了!这篇文章对我学习C++多线程很有帮助!谢谢
并发学习之一_windows下ZThread在CodeBlocks上的安装与配置
伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert Tarjan创造。它的优势在于不需要记录用于平衡树的冗余信息。在伸展树上的一般操作都基于伸展操作。
为什么需要伸展树(Splay Tree)
各种查找树存在不足。比如:对于一个有n个节点的平衡树,虽然最坏情况下每次查找的时间复杂度不会超过O(logn),但是如果访问模式不均匀,平衡树的效率就会受到影响。此外,它们还需要额外的空间来存储平衡信息。
这些查找树的设计目标都是减少最坏情况下单次操作时间,但是查找树的典型应用经常需要执行一系列的查找操作,此时更关心的性能指标是所有这些操作总共需要多少时间。对于此类应用,更好的目标就是降低操作的摊平时间,此处的摊平时间是指在一系列最坏情况的操作序列中单次操作的平均时间。获得摊平效率的一种方法就是使用“自调整”的数据结构。
和平衡的或是其它对结构有明确限制的数据结构比起来,自调整数据结构有以下几个优点:
1、从摊平角度而言,它们忽略常量因子,因此绝对不会比有明确限制的数据结构差。而且由于它们可以根据使用情况进行调整,于是在使用模式不均匀的情况下更加有效。
2、由于无需存储平衡或者其它的限制信息,它们所需的空间更小。
3、它们的查找和更新算法概念简单,易于实现。
当然,自调整结构也有潜在的缺点:
1、它们需要更多的局部调整,尤其是在查找期间。(那些有明确限制的数据结构仅需在更新期间进行调整,查找期间则不用)
2、一系列查找操作中的某一个可能会耗时较长,这在实时应用程序中可能是个不足之处。
什么是伸展树(Splay Tree)
假设想要对一个二叉查找树执行一系列的查找操作。为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法,在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。splay tree应运而生。splay tree是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。
两种重构方法:
1、单旋:在查找完位于节点x中的条目i之后,旋转链接x和其父节点的边。(除非x就是树根)
2、搬移至树根:在查找完位于节点x中的条目i之后,旋转链接x和其父节点的边,然后重复这个操作直至x成为树根。
旋转示意图:
注:
x为p(x)的左孩子,交换x和p(x)的位置,称为:右旋p(x)
x为p(x)的右孩子,交换x和p(x)的位置,称为:左旋p(x)
伸展树的自底向上伸展(bottom-up splay)
splay tree的重构方法和搬移至树根的方法相似,它也会沿着查找路径做自底向上的旋转,将被查找条目移至树根。但不同的是,它的旋转是成对进行的,顺序取决于查找路径的结构。为了在节点x处对树进行splay操作,我们需要重复下面的步骤,直至x成为树根为止:
注:图中 R-当前节点 Q-父亲节点 P-祖父节点
1、第一种情况:如果x的父节点p(x)是树根,则旋转连接x和p(x)的边。(这种情况是最后一步)
2、第二种情况:如果p(x)不是树根,而且x和p(x)本身都是左孩子或者都是右孩子,则先旋转连接p(x)和x的祖父节点g(x)的边,然后再旋转连接x和p(x)的边。
3、第三种情况:如果p(x)不是树根,而且x是左孩子,p(x)是右孩子,或者相反,则先旋转连接x和p(x)的边,再旋转连接x和新的p(x)的边。
在节点x处进行splay操作的时间是和查找x所需的时间成比例的。splay操作不单是把x搬移到了树根,而且还把查找路径上的每个节点的深度都大致减掉了一半。
伪代码:
假设在当前伸展树中的X节点处进行伸展, X的父亲节点为P(X) (如果X的父亲节点存在),
X的祖父节点为 G(X)(如果 X的祖父节点存在)。
FUNC bottom-up-splay
DO
IF X 是 P(X)的左孩子节点 THEN
IF G(X)为空 THEN
右旋 P(X)
ELSEIF P(X)是 G(X)的左孩子节点 THEN
右旋 G(X)
右旋 P(X)
ELSE
右旋 P(X)
左旋 P(X)(注意:经过上一次右旋后此处的 P(X)和上一个 P(X)不一样)
ENDIF
ELSE X是 P(X)的右孩子节点 THEN
IF G(X)为空 THEN
左旋 P(X)
ELSEIF P(X)是 G(X)的右孩子节点 THEN
左旋 G(X)
左旋 P(X)
ELSE
左旋 P(X)
右旋 P(X) (注意:经过上一次左旋后此处的 P(X)和上一个 P(X)不一样)
ENDIF
ENDIF
WHILE P(X)不为空
ENDFUNC
伸展树的自顶向下伸展(top-down splay)
自顶向下伸展操作将伸展树分为三部分:
左树:包含所有已经知道比待查节点 X小的节点。
右树:包含所有已经知道比待查节点 X大的节点。
中树:包含所有其它节点。
在中树自根向下进行节点查找(每次向下比较两个节点),根据查找情况将中树中的节
点移动(此处的移动是指将节点和中树的连接断开,而将节点连接到左或右树的适当位置。)到左树或右树(如有必要则会先对中树进行旋转再进行节点移动)。
初始状态时,左树和右树都为空,而中树为整个原伸展树。随着查找的进行,左树和右
树会因节点的逐渐移入变大,中树会因节点的逐渐移出变小。最后查找结束(找到或遇到空
节点)时组合左中右树并是伸展树自顶向下伸展方法的最终结果。
有四种情况:
1,孩子即为要查找的点,只需要一次连接操作即可.
2,孙子为要查找的点,且左右孩子一致.需要首先旋转父亲和祖父节点,然后连接操作.
3,孙子为要查找的点,且左右孩子不一致.需要两次连接操作.
4,合并
伪代码:
其中的 L、R 分别表示左树和右树且初始值为空,M 为中树且初值为原伸展树;X为待查节点,T 为 M 的根节点。
FUNC top-down-splay
DO
IF X 小于 T THEN
IF X 等于 T 的左孩子 THEN
右连接
ELSEIF X 小于 T 的左孩子 THEN
右旋
右连接
ELSE X大于 T 的左孩子 THEN
右连接
左连接
ENDIF
ELSE X大于 T THEN
IF X 等于 T 的右孩子 THEN
左连接
ELSEIF X 大于 T 的右孩子 THEN
左旋
左连接
ELSE X小于 T 的右孩子 THEN
左连接
右连接
ENDIF
ENDIF
WHILE 找到 X或遇到空节点
组合左中右树
ENDFUNC
伸展树(Splay Tree)支持的操作
具体操作包括:
1、access(i,t):如果i在树t中,则返回指向它的指针,否则返回空指针。为了实现 access(i,t),可以从树t的根部向下查找i。如果查找操作遇到了一个含有i的节点x,就在x处进行splay操作,并返回指向x的指针,访问结束。如果遇到了空指针,表示i不在树中,此时就在最后一个非空节点处进行splay操作,然后返回空指针。如果树是空的,将忽略掉splay操作。
2、insert(i,t):将条目i插入树t中(假设其尚不存在)。为了实现insert(i,t),首先执行split(i,t),然后把t换成一个由新的包含有i的根节点组成的树,这个根节点的左右子树分别是split返回的树t1和t2。
3、delete(i,t):从树t中删除条目i(假设其已经存在)。为了实现delete(i,t),首先执行access(i,t),然后把t换成其左子树和右子树join之后的新树。
4、join(t1,t2):将树t1和t2合并成一棵树,其中包含之前两棵树的所有条目,并返回合并之后的树。这个操作假设t1中的所有条目都小于t2 中的条目,操作完成之后会销毁t1和t2。为了实现join(t1,t2),首先访问t1中最大的条目i。访问结束之后,t1的根节点中包含的就是i,它的右孩子显然为空。于是把t2作为这个根节点的右子树并返回完成之后的新树即可实现join操作。
5、split(i,t):构建并返回两棵树t1和t2,其中t1包含t中所有小于等于i的条目,t2包含t中所有大于i的条目。操作完成之后销毁t。为了实现split(i,t),首先执行access(i,t),然后根据新根节点中的值是大于还是小于等于i来切断这个根节点的左链接或右链接,并返回形成的两棵树。
为什么需要伸展树(Splay Tree)
各种查找树存在不足。比如:对于一个有n个节点的平衡树,虽然最坏情况下每次查找的时间复杂度不会超过O(logn),但是如果访问模式不均匀,平衡树的效率就会受到影响。此外,它们还需要额外的空间来存储平衡信息。
这些查找树的设计目标都是减少最坏情况下单次操作时间,但是查找树的典型应用经常需要执行一系列的查找操作,此时更关心的性能指标是所有这些操作总共需要多少时间。对于此类应用,更好的目标就是降低操作的摊平时间,此处的摊平时间是指在一系列最坏情况的操作序列中单次操作的平均时间。获得摊平效率的一种方法就是使用“自调整”的数据结构。
和平衡的或是其它对结构有明确限制的数据结构比起来,自调整数据结构有以下几个优点:
1、从摊平角度而言,它们忽略常量因子,因此绝对不会比有明确限制的数据结构差。而且由于它们可以根据使用情况进行调整,于是在使用模式不均匀的情况下更加有效。
2、由于无需存储平衡或者其它的限制信息,它们所需的空间更小。
3、它们的查找和更新算法概念简单,易于实现。
当然,自调整结构也有潜在的缺点:
1、它们需要更多的局部调整,尤其是在查找期间。(那些有明确限制的数据结构仅需在更新期间进行调整,查找期间则不用)
2、一系列查找操作中的某一个可能会耗时较长,这在实时应用程序中可能是个不足之处。
什么是伸展树(Splay Tree)
假设想要对一个二叉查找树执行一系列的查找操作。为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置。于是想到设计一个简单方法,在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方。splay tree应运而生。splay tree是一种自调整形式的二叉查找树,它会沿着从某个节点到树根之间的路径,通过一系列的旋转把这个节点搬移到树根去。
两种重构方法:
1、单旋:在查找完位于节点x中的条目i之后,旋转链接x和其父节点的边。(除非x就是树根)
2、搬移至树根:在查找完位于节点x中的条目i之后,旋转链接x和其父节点的边,然后重复这个操作直至x成为树根。
旋转示意图:
注:
x为p(x)的左孩子,交换x和p(x)的位置,称为:右旋p(x)
x为p(x)的右孩子,交换x和p(x)的位置,称为:左旋p(x)
伸展树的自底向上伸展(bottom-up splay)
splay tree的重构方法和搬移至树根的方法相似,它也会沿着查找路径做自底向上的旋转,将被查找条目移至树根。但不同的是,它的旋转是成对进行的,顺序取决于查找路径的结构。为了在节点x处对树进行splay操作,我们需要重复下面的步骤,直至x成为树根为止:
注:图中 R-当前节点 Q-父亲节点 P-祖父节点
1、第一种情况:如果x的父节点p(x)是树根,则旋转连接x和p(x)的边。(这种情况是最后一步)
2、第二种情况:如果p(x)不是树根,而且x和p(x)本身都是左孩子或者都是右孩子,则先旋转连接p(x)和x的祖父节点g(x)的边,然后再旋转连接x和p(x)的边。
3、第三种情况:如果p(x)不是树根,而且x是左孩子,p(x)是右孩子,或者相反,则先旋转连接x和p(x)的边,再旋转连接x和新的p(x)的边。
在节点x处进行splay操作的时间是和查找x所需的时间成比例的。splay操作不单是把x搬移到了树根,而且还把查找路径上的每个节点的深度都大致减掉了一半。
伪代码:
假设在当前伸展树中的X节点处进行伸展, X的父亲节点为P(X) (如果X的父亲节点存在),
X的祖父节点为 G(X)(如果 X的祖父节点存在)。
FUNC bottom-up-splay
DO
IF X 是 P(X)的左孩子节点 THEN
IF G(X)为空 THEN
右旋 P(X)
ELSEIF P(X)是 G(X)的左孩子节点 THEN
右旋 G(X)
右旋 P(X)
ELSE
右旋 P(X)
左旋 P(X)(注意:经过上一次右旋后此处的 P(X)和上一个 P(X)不一样)
ENDIF
ELSE X是 P(X)的右孩子节点 THEN
IF G(X)为空 THEN
左旋 P(X)
ELSEIF P(X)是 G(X)的右孩子节点 THEN
左旋 G(X)
左旋 P(X)
ELSE
左旋 P(X)
右旋 P(X) (注意:经过上一次左旋后此处的 P(X)和上一个 P(X)不一样)
ENDIF
ENDIF
WHILE P(X)不为空
ENDFUNC
伸展树的自顶向下伸展(top-down splay)
自顶向下伸展操作将伸展树分为三部分:
左树:包含所有已经知道比待查节点 X小的节点。
右树:包含所有已经知道比待查节点 X大的节点。
中树:包含所有其它节点。
在中树自根向下进行节点查找(每次向下比较两个节点),根据查找情况将中树中的节
点移动(此处的移动是指将节点和中树的连接断开,而将节点连接到左或右树的适当位置。)到左树或右树(如有必要则会先对中树进行旋转再进行节点移动)。
初始状态时,左树和右树都为空,而中树为整个原伸展树。随着查找的进行,左树和右
树会因节点的逐渐移入变大,中树会因节点的逐渐移出变小。最后查找结束(找到或遇到空
节点)时组合左中右树并是伸展树自顶向下伸展方法的最终结果。
有四种情况:
1,孩子即为要查找的点,只需要一次连接操作即可.
2,孙子为要查找的点,且左右孩子一致.需要首先旋转父亲和祖父节点,然后连接操作.
3,孙子为要查找的点,且左右孩子不一致.需要两次连接操作.
4,合并
伪代码:
其中的 L、R 分别表示左树和右树且初始值为空,M 为中树且初值为原伸展树;X为待查节点,T 为 M 的根节点。
FUNC top-down-splay
DO
IF X 小于 T THEN
IF X 等于 T 的左孩子 THEN
右连接
ELSEIF X 小于 T 的左孩子 THEN
右旋
右连接
ELSE X大于 T 的左孩子 THEN
右连接
左连接
ENDIF
ELSE X大于 T THEN
IF X 等于 T 的右孩子 THEN
左连接
ELSEIF X 大于 T 的右孩子 THEN
左旋
左连接
ELSE X小于 T 的右孩子 THEN
左连接
右连接
ENDIF
ENDIF
WHILE 找到 X或遇到空节点
组合左中右树
ENDFUNC
伸展树(Splay Tree)支持的操作
具体操作包括:
1、access(i,t):如果i在树t中,则返回指向它的指针,否则返回空指针。为了实现 access(i,t),可以从树t的根部向下查找i。如果查找操作遇到了一个含有i的节点x,就在x处进行splay操作,并返回指向x的指针,访问结束。如果遇到了空指针,表示i不在树中,此时就在最后一个非空节点处进行splay操作,然后返回空指针。如果树是空的,将忽略掉splay操作。
2、insert(i,t):将条目i插入树t中(假设其尚不存在)。为了实现insert(i,t),首先执行split(i,t),然后把t换成一个由新的包含有i的根节点组成的树,这个根节点的左右子树分别是split返回的树t1和t2。
3、delete(i,t):从树t中删除条目i(假设其已经存在)。为了实现delete(i,t),首先执行access(i,t),然后把t换成其左子树和右子树join之后的新树。
4、join(t1,t2):将树t1和t2合并成一棵树,其中包含之前两棵树的所有条目,并返回合并之后的树。这个操作假设t1中的所有条目都小于t2 中的条目,操作完成之后会销毁t1和t2。为了实现join(t1,t2),首先访问t1中最大的条目i。访问结束之后,t1的根节点中包含的就是i,它的右孩子显然为空。于是把t2作为这个根节点的右子树并返回完成之后的新树即可实现join操作。
5、split(i,t):构建并返回两棵树t1和t2,其中t1包含t中所有小于等于i的条目,t2包含t中所有大于i的条目。操作完成之后销毁t。为了实现split(i,t),首先执行access(i,t),然后根据新根节点中的值是大于还是小于等于i来切断这个根节点的左链接或右链接,并返回形成的两棵树。
发表评论
-
为什么堆排比快排慢
2010-12-16 15:25 3034[节选]http://mindhacks.cn/200 ... -
使用map和hash_map的效率问题
2010-12-09 19:49 68961,选择map容器,是为了更快的从关键字查找到相关的对象。 与 ... -
斐波那契堆
2010-07-04 11:37 181, http://kmplayer.iteye.com/ad ... -
斐波那契堆
2010-07-04 11:36 1437学习的地方: http://en.wikipedia.org/ ... -
Sunday算法
2010-07-02 11:38 90021,Sunday算法是Daniel M.Sunday于1990 ... -
BM算法.
2010-07-02 10:53 77261,BM算法是Boyer-Moore算法的简称,由Boyer ... -
优先级队列
2010-06-17 23:15 12071,优先级队列是不同于 ... -
计数排序
2010-05-04 16:59 7901,计数排序是一个非基于比较的线性时间排序算法。 它对输入的数 ... -
归并排序
2010-05-04 16:47 9071,归并排序是建立在归并操作上的一种有效的排序算法。该算法是采 ... -
求大数阶层
2010-05-04 16:40 13511,思想类似于大数的加减乘法. 数组的每个元素维护一个4位数. ... -
基数排序
2010-05-03 16:45 898详细解释参考:http://en.wikipedia.org/ ... -
求两个数组的中位数
2010-05-02 12:08 41241,题目 有两个数组,均已经按升序排列好,编程序计算这两个数组 ... -
imba的bit向量
2010-04-22 17:30 9451,先给出一个模板. #include <iostr ... -
编写自己的malloc
2010-04-19 17:03 15261,如果一个程序大量调用malloc,程序的很多时间将会消耗在 ... -
快速排序
2010-04-01 13:50 7481,给出一个实现实例. #include <iost ... -
md5算法
2010-03-31 10:35 2689Message Digest Algorithm MD5( ... -
堆排序
2010-03-23 10:48 9001,"堆"定义 n个关 ... -
改进的线性筛法_寻找素数
2010-03-03 10:41 16231,实例代码: #include <iostream ... -
求有向图的强连通分量(scc):Tarjan算法
2010-02-28 15:41 143301,在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强 ... -
最近公共祖先LCA:Tarjan算法
2010-02-28 15:25 178611,并查集+dfs 对整个树进行深度优先遍历,并在遍历的过程中 ...
相关推荐
### 伸展树的基本操作与应用 #### 引言 伸展树,又称Splay Tree,是由Daniel Sleator和Robert Tarjan在1985年提出的自调整二叉搜索树。与传统二叉搜索树相比,伸展树的显著特点是其能够通过一系列的旋转操作自动...
伸展树,又称Splay Tree,是一种自调整的二叉搜索树。它的设计目标是通过局部操作优化查找、插入和删除等操作的时间复杂度,使得常用的数据更容易访问,从而提高整体性能。在C++中实现伸展树,可以极大地利用其模板...
伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由丹尼尔·斯立特Daniel Sleator 和 罗伯特·恩卓·塔扬Robert Endre Tarjan 在1985年发明的。 [1] 在伸展树上...
### 伸展树(Splay Tree)详解 #### 一、伸展树简介 **伸展树**(Splay Tree)是一种特殊的二叉搜索树(Binary Search Tree),它能够在平均情况下达到 O(log n) 的时间复杂度,对于插入、查找和删除操作均适用。...
在这个场景下,“伸展树”(Splay Tree)是解决这个问题的关键数据结构。伸展树是一种自调整的二叉搜索树,它通过特定的重排策略(伸展操作)来优化频繁访问的节点,使得常用节点能够更快地被访问到,从而提高整体...
### 伸展树(Splay Tree)概述 伸展树(Splay Tree)是一种自调整的二叉搜索树,由Daniel Sleator和Robert Tarjan在1985年提出。其核心思想是在每次访问节点后,通过一系列的旋转操作将被访问的节点调整到树根的位置...
伸展树,又称为自平衡二叉查找树(Self-Balancing Binary Search Tree),是一种用于高效存储和检索数据的数据结构。它的主要特点是通过特定的旋转操作(如左旋、右旋、双旋等)来自动调整树的形态,使得最近访问的...
splay 伸展树.ppt
算法合集之《伸展树的基本操作与应用》.ppt
伸展树是一种自平衡的二叉搜索树,它可以在O(log n)的时间复杂度内完成查找、插入和删除等操作,并且具有独特的特性——伸展操作,使得最近访问过的节点容易再次被访问。在数列维护问题中,伸展树能够提供比线段树更...
伸展树(Splay Tree)是一种自调整的二叉搜索树,由Daniel Sleator和Robert Tarjan在1985年提出。它通过特定的旋转操作(如左旋、右旋和双旋)来重新组织树,使得最近访问的节点更靠近根部,从而在连续的访问中提高...
伸展树,也称为可折叠/可伸展树,是树型菜单的一个特定实现,允许用户通过点击图标(通常是加号"+"或减号"-")来展开或收起子节点,从而提高用户交互的效率和界面的清晰度。 伸展树的基本结构是由节点组成的,每个...
伸展树是一种特殊的二叉搜索树,它通过一系列的旋转操作来维护树的平衡性,保证频繁访问的节点能够更快速地被检索到。在计算机科学的数据结构领域,伸展树是一种功能强大的数据结构,尤其在处理动态数据集时,它可以...
伸展树作为一种自调整的二叉搜索树,因其在动态数据集合操作中的高效性而被广泛采用。本文旨在深入分析伸展树的原理和实际应用,并讨论其在ACM竞赛中的重要性。 首先,伸展树通过特定的伸展操作来优化数据结构的...
伸展树(Splay Tree)是一种自调整的二叉搜索树数据结构,它通过操作将最近访问的元素移动到树的根部,从而优化查找、插入和删除等操作的平均性能。C#语言中的伸展树实现涉及了对二叉树节点的操作、旋转算法以及对树...
伸展树(Splay Tree)是一种自调整的二叉搜索树,它的设计目标是通过一系列的旋转操作来优化频繁访问的节点,使得常用节点更靠近根部,从而提高查询、插入和删除等操作的平均性能。伸展树的核心思想是“最近最常使用...
【伸展树(Splay Tree)】是一种自调整的二叉查找树,它通过特定的“伸展”操作来优化查找、插入和删除等操作的性能。伸展树不是一种新的数据结构,而是对普通二叉查找树的一种优化策略,旨在在最坏的情况下也能保持...