本文用势能法证明\(Splay\)的均摊复杂度,对\(Splay\)的具体操作不进行讲述。

为了方便本文的描述,定义如下内容:

在文中我们用\(T\)表示一棵完整的\(Splay\),并(不严谨地)用\(|T|\)表示\(T\)这棵\(Splay\)的节点数目。

如无特殊说明,小写英文字母(如\(x\),\(y\),\(z\))在本文中表示\(T\)的一个节点,并(不严谨地)用\(|x|\)表示以节点\(x\)为根的子树的大小,\(x\in T\)表示节点\(x\)在\(T\)中。

一般我们默认\(x'\)代表节点\(x\)在经过了上下文中描述的操作以后的状态,因此对应的\(x\)代表之前的状态。

我们用\(\Phi(T)\)表示整棵\(Splay\)的势能函数,\(\phi(x)\)则表示节点\(x\)对\(T\)贡献的势能。

=============================================

先来讲一下我们的势能函数,我们定义:

\[\phi(x)=\log|x|\]

\[\Phi(T)=\sum_{x\in T}\phi(x)\]

可以发现,对于任意时刻,因为\(|x|\geq 1\),因此\(\log|x|\geq 0\),从而得到\(\Phi(T)\geq 0\),因此势能函数是合法的。同时\(\forall |x|\leq |T|\),因此我们总有\(\Phi(T)\leq |T|\log|T|\)。这个上界是比较松的,但是对我们的分析没有影响。

下面考虑一次伸展操作对于势能函数的影响。由于我们可以把从根向下查找的代价计算到伸展过程中对应的旋转操作上,此时旋转操作复杂度不变,只是常数增大,从而忽略了查找对复杂度的影响。我们可以简单地通过增大势的单位来支配隐藏在操作中的常数。因此我们只需证明对于一次伸展操作的所有旋转操作,其复杂度是均摊\(O(\log|T|)\)的,我们就完成了对\(Splay\)复杂度的证明。

\(1\)、\(zig\)操作

由于\(zag\)操作与\(zig\)相似,因此只需要证明\(zig\)即可。

假设我们\(zig\)的对象是\(x\),其父亲为\(y\),显然在旋转以后,只有\(x\)和\(y\)的子树大小发生了变化。因此势能变化量为:

\[\Delta\Phi(T)=\phi(x')+\phi(y')-\phi(x)-\phi(y)\]

显然\(\phi(x')=\phi(y)\),且\(\phi(x')\geq \phi(y')\),因此消去\(\phi(x')\)与\(\phi(y)\),并将\(\phi(y')\)替换为\(\phi(x')\),有:

\[\Delta\Phi(T)\leq \phi(x')-\phi(x)\]

因此\(zig\)操作的均摊代价为\(O(1+\phi(x')-\phi(x))\),其中\(O(1)\)代表旋转操作本身的复杂度,而在一次伸展操作中也只会有一次\(zig\)操作,因此这额外的\(O(1)\)代价不会对分析造成影响,因此我们可以只关心其中的\(O(\phi(x')-\phi(x))\)。

\(2\)、\(zig-zig\)操作

由于\(zag-zag\)操作与\(zig-zig\)相似,因此只需要证明\(zig-zig\)即可。

假设我们\(zig-zig\)的对象是\(x\),其父亲为\(y\),其祖父为\(z\),与\(zig\)操作类似,势能变化量为:

\[\Delta\Phi(T)=\phi(x')+\phi(y')+\phi(z')-\phi(x)-\phi(y)-\phi(z)\]

同样地,由于\(\phi(x')=\phi(z)\),因此将它们消去:

\[\Delta\Phi(T)=\phi(y')+\phi(z')-\phi(x)-\phi(y)\]

而我们又有\(\phi(x')\geq \phi(y')\),\(\phi(x)\leq \phi(y)\),因此有:

\[\Delta\Phi(T)\leq \phi(x')+\phi(z')-2\phi(x)\]

推到这里,我们先来做一个小工作,来证明\(\phi(x)+\phi(z')-2\phi(x')\)(注意与上面的式子不一样)的值不大于\(-1\)。

假设\(|x|=a\),\(|z'|=b\),那么我们有:

\[\phi(x)+\phi(z')-2\phi(x')=\log|x|+\log|z'|-2\log|x'|\]

我们将\(\log\)合并,得到:

\[\phi(x)+\phi(z')-2\phi(x')=\log(\frac{|x||z'|}{|x'|^2})\]

由于\(|x'|\geq a+b\)(可以结合旋转过程思考一下),而\(\log\)是单调的,因此:

\[\phi(x)+\phi(z')-2\phi(x')\leq \log(\frac{ab}{(a+b)^2})\leq \log(\frac{ab}{2ab})\leq -1\]

证明完毕。现在我们已经知道\(zig-zig\)操作的摊还代价不大于:

\[O(1)+\phi(x')+\phi(z')-2\phi(x)\]

其中\(O(1)\)为旋转操作的复杂度。由于之前的推导我们可以知道\(\phi(x)+\phi(z')-2\phi(x')\leq -1\),因此\(-1-(\phi(x)+\phi(z')-2\phi(x'))\geq 0\),我们在摊还代价上加上这个非负数得到:

\[O(1)+\phi(x')+\phi(z')-2\phi(x)-1-(\phi(x)+\phi(z')-2\phi(x'))\]

化简一下,就得到:

\[O(1)+O(\phi(x')-\phi(x))-1\]

通过增大我们刚刚加的那个非负数以及势的单位,我们就可以支配隐藏在\(O(1)\)中的常数,因此一次\(zig-zig\)操作的摊还代价为:

\[O(\phi(x')-\phi(x))\]

\(3\)、\(zig-zag\)操作

分析的过程和\(zig-zig\)操作完全一样,之前分析用到的所有性质此时仍然适用,因此略过分析过程。其摊还代价依然为:

\[O(\phi(x')-\phi(x))\]

\(4\)、总结

综上所述,除了最后一次旋转可能增加\(O(1)\)的代价以外,其余操作的摊还代价只和我们伸展的对象\(x\)的势有关。我们假设旋转操作一共执行了\(n\)次,并用\(x_i\)来表示节点\(x\)在经过\(i\)次旋转后的状态,那么整一个伸展操作的摊还代价就为:

\[O\Big(1+\sum_{i=1}^n\phi(x_i)-\phi(x_{i-1})\Big)\]

显然除了\(\phi(x_n)\)与\(\phi(x_0)\)外,所有的势都被抵消了,因此摊还代价为:

\[O(1+\phi(x_n)-\phi(x_0))\]

至此,我们不必关心\(\phi(x_0)\)的值了。此时\(x_n\)是整棵\(Splay\)的根,因此\(\phi(x_n)=\log|T|\)。我们成功的证明了一次伸展操作的摊还代价为\(O(\log|T|)\)。

伸展树(Splay)复杂度证明的更多相关文章

  1. 纸上谈兵: 伸展树 (splay tree)[转]

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢!  我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每 ...

  2. K:伸展树(splay tree)

      伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(lgN)内完成插入.查找和删除操作.在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使 ...

  3. 高级搜索树-伸展树(Splay Tree)

    目录 局部性 双层伸展 查找操作 插入操作 删除操作 性能分析 完整源码 与AVL树一样,伸展树(Splay Tree)也是平衡二叉搜索树的一致,伸展树无需时刻都严格保持整棵树的平衡,也不需要对基本的 ...

  4. 树-伸展树(Splay Tree)

    伸展树概念 伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.它由Daniel Sleator和Robert Tarjan创造. (01) 伸展树属于二 ...

  5. [Splay伸展树]splay树入门级教程

    首先声明,本教程的对象是完全没有接触过splay的OIer,大牛请右上角.. 首先引入一下splay的概念,他的中文名是伸展树,意思差不多就是可以随意翻转的二叉树 PS:百度百科中伸展树读作:BoGa ...

  6. 伸展树(Splay tree)的基本操作与应用

    伸展树的基本操作与应用 [伸展树的基本操作] 伸展树是二叉查找树的一种改进,与二叉查找树一样,伸展树也具有有序性.即伸展树中的每一个节点 x 都满足:该节点左子树中的每一个元素都小于 x,而其右子树中 ...

  7. 【BBST 之伸展树 (Splay Tree)】

    最近“hiho一下”出了平衡树专题,这周的Splay一直出现RE,应该删除操作指针没处理好,还没找出原因. 不过其他操作运行正常,尝试用它写了一道之前用set做的平衡树的题http://codefor ...

  8. 伸展树Splay【非指针版】

    ·伸展树有以下基本操作(基于一道强大模板题:codevs维护队列): a[]读入的数组;id[]表示当前数组中的元素在树中节点的临时标号;fa[]当前节点的父节点的编号;c[][]类似于Trie,就是 ...

  9. ZOJ 3765 Lights (zju March I)伸展树Splay

    ZJU 三月月赛题,当时见这个题目没辙,没学过splay,敲了个链表TLE了,所以回来好好学了下Splay,这道题目是伸展树的第二题,对于伸展树的各项操作有了更多的理解,这题不同于上一题的用指针表示整 ...

  10. [数据结构]伸展树(Splay)

    #0.0 写在前面 Splay(伸展树)是较为重要的一种平衡树,理解起来也依旧很容易,但是细节是真的多QnQ,学一次忘一次,还是得用博客加深一下理解( #1.0 Splay! #1.1 基本构架 Sp ...

随机推荐

  1. 20155217《网络对抗》Exp02 后门原理与实践

    20155217<网络对抗>Exp02 后门原理与实践 实验要求 使用netcat获取主机操作Shell,cron启动. 使用socat获取主机操作Shell,任务计划启动. 使用MSF ...

  2. VS编程,WPF中,获取鼠标相对于当前屏幕坐标的一种方法

    原文:VS编程,WPF中,获取鼠标相对于当前屏幕坐标的一种方法 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/det ...

  3. EZ 2018 02 28 NOIP2018 模拟赛(二)

    我TM的终于改完了(其实都是SB题) 题目链接:http://211.140.156.254:2333/contest/53 T1送分,T2前40%送分,还有骗分机制在里面,T3暴力50 所以200应 ...

  4. 【SP1812】LCS2 - Longest Common Substring II

    [SP1812]LCS2 - Longest Common Substring II 题面 洛谷 题解 你首先得会做这题. 然后就其实就很简单了, 你在每一个状态\(i\)打一个标记\(f[i]\)表 ...

  5. [UOJ#276][清华集训2016]汽水[分数规划+点分治]

    题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...

  6. JQ_开发经验

    1. 把你的代码全部放在闭包里面 这是我用的最多的一条.但是有时候在闭包外面的方法会不能调用.不过你的插件的代码只为你自己的插件服务,所以不存在这个问题,你可以把所有的代码都放在闭包里面.而方法可能应 ...

  7. Kafka高性能吞吐关键技术分析

    Apache Kafka官网提供的性能说明: Benchmarking Apache Kafka: 2 Million Writes Per Second (On Three Cheap Machin ...

  8. Vim操作指南

    vim具有6种基本模式和5种派生模式. 基本模式 普通模式 插入模式 可视模式 选择模式 命令行模式 Ex模式 派生模式 操作符等待模式 插入普通模式 插入可视模式 插入选择模式 替换模式 1.移动光 ...

  9. (Alpha)Let's-典型用户和场景&功能规格说明书

    典型用户和场景 Personal/典型用户 名字 阿王 性别.年龄 男.20 职业 学生 收入 无 知识层次和能力 大学学生,善于乐于使用电脑.手机 生活/工作情况 上学 动机.目的.困难 感到大学生 ...

  10. ElasticSearch 2 (20) - 语言处理系列之如何开始

    ElasticSearch 2 (20) - 语言处理系列之如何开始 摘要 Elasticsearch 配备了一组语言分析器,为世界上大多数常见的语言提供良好的现成基础支持. 阿拉伯语.亚美尼亚语,巴 ...