伸展树的特性及实现

标签: 二叉树 搜索树 伸展树
4人阅读 评论(0) 收藏 举报
分类:

除了AVL树,本章将按照二叉搜索树的介绍,继续介绍平衡二叉搜索树家族中的另一个成员—Splay伸展树。

相对于AVL,Splay的实现更为简捷。伸展树无需时刻都严格地保持全树的平衡,但却能够在任何足够长的真实操作序列中,保持分摊意义上的高效率。伸展树也不需要对基本的二叉树节点结构,做任何附加的要求或改动,更不需要记录平衡因子或高度之类的额外信息,故适用范围更广。

通常在任意数据结构的生命期内,执行不同操作的概率往往极不均衡,而且各操作之间具有极强的相关性,并在整体上多呈现出极强的规律性。其中最为典型的,就是所谓的“数据局部性”(data locality),这包括两个方面的含义:

  • 刚刚被访问过的元素,极有可能在不久之后再次被访问到
  • 将被访问的下一元素,极有可能就处于不久之前被访问过的某个元素的附近

如果将该策略应用于二叉搜索树。只需将刚被访问的节点,及时地“转移”至树根(附近),即可加速后续的操作。当然, 转移前后的搜索树必须相互等价,故为此使用前文介绍的“旋转“等价变换的技巧。

逐层伸展

每访问过一个节点之后,随即反复地以它的父节点为轴,经适当的旋转将其提升一层,直至最终成为树根。以下图为例,若深度为3的节点E刚被访问–无论查找或插入,甚至“删除”都可通过3次旋转,将该树等价变换为以E为根的另一棵二叉搜索树
这里写图片描述

随着节点E的逐层上升,两侧子树的结构也不断地调整,故这一过程也形象地称作伸展 (splaying),而采用这一调整策略的二叉搜索树也因此得名。不过,为实现真正意义上的伸 展树,还须对以上策略做点微妙而本质的改进。之所以必须改进,是因为目前的策略仍存在致命 的缺陷—对于很多访问序列,单次访问的分摊时间复杂度在极端情况下可能高达n。

不难验证,若从空树开始依次插入关键码{ 1, 2, 3, 4, 5 },且其间采用如上调整策略,
则可得到如下图所示的二叉搜索树。

这里写图片描述

在各次访问之后,为将对应节点伸展调整至树根,分别需做4、4、3、2和1次旋转。

一般地,若节点总数为n,则旋转操作的总次数应为:
(n - 1) + { (n - 1) + (n - 2) + … + 1 }= (n2 +n-2)/2 = n的平方。

如此分摊下来,每次访问平均需要n时间。很遗憾,这一效率不仅远远低于AVL树,而且甚至与原始的二叉搜索树的最坏情况相当。

而事实上,问题还远不止于此。稍做比对即不难发现,上图a与f中二叉搜索树的结构完全相同。也就是说,经过以上连续的5次访问之后,全树的结构将会复原!
这就意味着,以上情况可以持续地再现。
当然,这一实例,完全可以推广至规模任意的二叉搜索树。于是对于规模为任意n的伸展树, 只要按关键码单调的次序,周期性地反复进行查找,则无论总的访问次数m >> n有多大,就分摊意义而言,每次访问都将需要n时间!

双层伸展

为克服上述伸展调整策略的缺陷,一种简便且有效的方法就是:将逐层伸展改为双层伸展。 具体地,每次都从当前节点v向上追溯两层(而不是仅一层),并根据其父亲p以及祖父g的相对位置,进行相应的旋转。主要以下分三类情况:

zig-zig/zag-zag

如下图所示, 设v是p的左孩子,且p也是g的左孩子;
设W和X分别是v的左、右子树,Y和Z分别是p和g的右子树。

这里写图片描述

针对这种情况,首先以节点g为轴做顺时针旋转zig(g),其效果如图(b)所示。然后,再以p
为轴做顺时针旋转zig(p),其效果如图(c)所示。如此连续的两次zig旋转,合称zig-zig调整。 自然地,另一完全对称的情形,v是p的右孩子,且p也是g的右孩子,则可通过连续的
两次逆时针旋转实现调整,合称zag-zag操作。

zig-zag/zag-zig

如下图所示,设v是p的左孩子,而p是g的右孩子;
设W是g的左子树,X和Y分别是v的左右子树,Z是p的右子树。

这里写图片描述

针对这种情况,首先以节点p为轴做顺时针旋转zig(p),其效果如(b)所示。然后,再以g
为轴做逆时针旋转zag(g),其效果如图(c)所示。如此zig旋转再加zag旋转,合称zig-zag调整。 同样地,另一完全对称的情形–v是p的右孩子,而p是g的左孩子—则可通过zag旋转再加zig旋转实现调整,合称zag-zig操作。

zig/zag

如下图所示,若v最初的深度为奇数,则经过若干次双层调整至最后一次调整时,
v的父亲p即是树根r。
这里写图片描述
将v的左、右子树记作X和Y,节点p = r的另一子树记作Z。
此时,只需围绕p = r做顺时针旋转zig(p),即 可如图(b)所示,使v最终攀升至树根,从而结束整个伸展调整的过程。

综合以上各种情况,每经过一次双层调整操作,节点v都会上升两层。若v的初始深度depth(v) 为偶数,则最终v将上升至树根。若depth(v)为奇数,则当v上升至深度为1时,不妨最后再相应 地做一次zig或zag单旋操作。无论如何,经过depth(v)次旋转后,v最终总能成为树根。

回顾最开始的单层伸展的例子中:在可持续重复的过程中,二叉搜索树的高度始终不小于n/2; 而且,至少有一半的节点在接受访问时,不仅没有如最初设想的那样靠近树根,而且反过来恰恰处于最底层。 从树高的角度看,问题根源也可再进一步地解释为:在持续访问的过程中,树高依算术级数逐步从n - 1递减至n/2,然后再逐步递增回到n - 1。

以如下图所示的二叉搜索树为例,在find(1)操作之后,采用逐层调整策略与双层调 整策略的效果,分别如图(a)和图(c)所示。

这里写图片描述

可见,最深节点(1)被访问之后再经过双层调整,不仅同样可将该节点伸展至树根,而且同时可使树的高度接近于减半。就树的形态而言,双层伸展策略可“智能”地“折叠”被访问的 子树分支,从而有效地避免对长分支的连续访问。这就意味着,即便节点v的深度为n,双层 伸展策略既可将v推至树根,亦可令对应分支的长度以几何级数(大致折半)的速度收缩。

查看评论

Android 5.0的特性

-
  • 1970年01月01日 08:00

伸展树详解及实现(C语言)

1.什么是伸展树 简单的说,伸展树是一棵二叉查找树,对每个节点的访问,都要将该节点通过旋转操作,把它翻转到根处。然后进行操作。下图是访问关键字1的过程(自底向上翻转)。可以看到伸展的...
  • xiaohusaier
  • xiaohusaier
  • 2017-07-27 10:29:05
  • 434

伸展树的原理及实现源代码(有图文详解和C++实现代码)

伸展树的原理及实现源代码(有图文详解和C++实现代码) 伸展树(Splay Tree)是一种二叉搜索树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert...
  • u013149325
  • u013149325
  • 2014-11-25 15:38:29
  • 2094

伸展树c++ 实现

一、为什么要有伸展树 根据
  • yinjingyu_bisheng
  • yinjingyu_bisheng
  • 2014-06-28 11:36:07
  • 1624

Java数据结构与算法解析(八)——伸展树

伸展树简介伸展树(Splay Tree)是特殊的二叉查找树。 它的特殊是指,它除了本身是棵二叉查找树之外,它还具备一个特点: 当某个节点被访问时,伸展树会通过旋转使该节点成为树根。这样做的好处是,下...
  • u012124438
  • u012124438
  • 2017-09-22 23:48:24
  • 8795

【伸展树】自顶向下写法

一般的伸展树都是自底向上的吧..
  • zhenaodingpao
  • zhenaodingpao
  • 2014-08-03 09:35:36
  • 574

bzoj1503: [NOI2004]郁闷的出纳员(伸展树)

题目传送门 基本也算入门题了。解法: 就伸展树维护一下然后加个暴力吧。代码实现:#include #include #include using namespace std; int root; ...
  • Hanks_o
  • Hanks_o
  • 2017-10-23 19:46:20
  • 251

伸展树(Splay tree)图解与实现

一、伸展树  本文介绍了二叉查找树的一种改进数据结构–伸展树(Splay Tree)。它的主要特点是不会保证树一直是平衡的,但各种操作的平摊时间复杂度是O(log n),因而,从平摊复杂度上看,二叉...
  • u014634338
  • u014634338
  • 2015-11-02 16:20:48
  • 5088

伸展树的旋转和伸展操作

伸展树(Splay Tree)是一种排序二叉树,其核心操作是伸展。所谓伸展就是把指定节点旋转至树根(同时保持排序二叉树性质)的过程。而伸展操作的基础就是旋转。     旋转是所有排序二叉树的基本操作,...
  • u012061345
  • u012061345
  • 2014-05-08 09:37:39
  • 1389

bzoj 1503: [NOI2004]郁闷的出纳员 (伸展树)

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 8015  Solved: 2819 [Submit][...
  • whai362
  • whai362
  • 2015-08-12 19:34:08
  • 979
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 67万+
    积分: 7867
    排名: 3346
    博客专栏
    最新评论