伸展树(Splay)复杂度证明
本文用势能法证明的均摊复杂度,对的具体操作不进行讲述。
为了方便本文的描述,定义如下内容:
在文中我们用表示一棵完整的,并(不严谨地)用表示这棵的节点数目。
如无特殊说明,小写英文字母(如,,)在本文中表示的一个节点,并(不严谨地)用表示以节点为根的子树的大小,表示节点在中。
一般我们默认代表节点在经过了上下文中描述的操作以后的状态,因此对应的代表之前的状态。
我们用表示整棵的势能函数,则表示节点对贡献的势能。
=============================================
先来讲一下我们的势能函数,我们定义:
可以发现,对于任意时刻,因为,因此,从而得到,因此势能函数是合法的。同时,因此我们总有。这个上界是比较松的,但是对我们的分析没有影响。
下面考虑一次伸展操作对于势能函数的影响。由于我们可以把从根向下查找的代价计算到伸展过程中对应的旋转操作上,此时旋转操作复杂度不变,只是常数增大,从而忽略了查找对复杂度的影响。我们可以简单地通过增大势的单位来支配隐藏在操作中的常数。因此我们只需证明对于一次伸展操作的所有旋转操作,其复杂度是均摊的,我们就完成了对复杂度的证明。
、操作
由于操作与相似,因此只需要证明即可。
假设我们的对象是,其父亲为,显然在旋转以后,只有和的子树大小发生了变化。因此势能变化量为:
显然,且,因此消去与,并将替换为,有:
因此操作的均摊代价为,其中代表旋转操作本身的复杂度,而在一次伸展操作中也只会有一次操作,因此这额外的代价不会对分析造成影响,因此我们可以只关心其中的。
、操作
由于操作与相似,因此只需要证明即可。
假设我们的对象是,其父亲为,其祖父为,与操作类似,势能变化量为:
同样地,由于,因此将它们消去:
而我们又有,,因此有:
推到这里,我们先来做一个小工作,来证明(注意与上面的式子不一样)的值不大于。
假设,,那么我们有:
我们将合并,得到:
由于(可以结合旋转过程思考一下),而是单调的,因此:
证明完毕。现在我们已经知道操作的摊还代价不大于:
其中为旋转操作的复杂度。由于之前的推导我们可以知道,因此,我们在摊还代价上加上这个非负数得到:
化简一下,就得到:
通过增大我们刚刚加的那个非负数以及势的单位,我们就可以支配隐藏在中的常数,因此一次操作的摊还代价为:
、操作
分析的过程和操作完全一样,之前分析用到的所有性质此时仍然适用,因此略过分析过程。其摊还代价依然为:
、总结
综上所述,除了最后一次旋转可能增加的代价以外,其余操作的摊还代价只和我们伸展的对象的势有关。我们假设旋转操作一共执行了次,并用来表示节点在经过次旋转后的状态,那么整一个伸展操作的摊还代价就为:
显然除了与外,所有的势都被抵消了,因此摊还代价为:
至此,我们不必关心的值了。此时是整棵的根,因此。我们成功的证明了一次伸展操作的摊还代价为。