替罪羊树的效率

(来自算法导论十七章摊还分析思考题 173,「摊还加权平衡树」)

想当年替罪羊树可能是我第一个学习的平衡树。。。但是很少有人说明它均摊 O(lgn) 的效率是从何而来,正巧在看算导的时候有这样一个题,遂开写。

这玩意是一种 Weighted Balance Tree,靠重构来维护一个均摊较好的性能。

具体地说,选一个在 12α<1 之间的一个常数 α 作为平衡因子。如果一个节点 u 的左右子树的大小都不大于 αsize(u),那么我们认为 uα 平衡的,若所有节点都是 α 平衡的那么这棵树就是 α 平衡的。

首先说明如果 T 对于 α (12α<1) 是平衡的,那么这棵树的树高是 O(lgn)。对于一个点 u 从根开始向下走,每向下走一步那么以它为根的子树大小至多乘上 α,叶子的大小为 1,即 nαh=1,得到 h=logα1n=log1αn=O(lgn)

如此我们就知道了一棵平衡的替罪羊树它的查询效率是 O(lgn) 的,接下来我们着重分析它是如何在插入操作中维护平衡。

对于节点 uT 及它的左右儿子 ul,ur 定义

Δ(u)=|size(ul)size(ur)|

定义势能函数

Φ(T)=uT,Δ(u)2Δ(u)2α1

首先证一个引理是对于 α=12 平衡的 T 的势能为 0。若势能大于 0 则存在 uT|size(ul)size(ur)|2,不妨设是 size(ul)size(ur)2,由于它是 12 平衡的,故有 size(ul)size(u)2=size(ul)+size(ur)+12size(ul)size(ur)+1,带到最初的式子中有 size(ur)+1size(ur)212 导出矛盾。

重构操作在 O(size(u)) 的时间下将 subtree(u) 重构为 12 平衡的,这可以直接像类似线段树建树的分治方法做到。下面我们将证明重构操作是均摊 O(1) 的。

重构操作的均摊代价为

c^=O(size(u))+ΔΦ(T)=O(size(u))+ΔΦ(subtree(u))=O(size(u))+0vsubtree(u),Δ(v)2Δ(v)2α1

我们考察 u 的情况,它是 α 不平衡的,不妨设 size(ur)>size(ul),则有

Δ(u)=size(ur)size(ul)αsize(u)+1(1α)size(u)+1=(2α1)size(u)+2

它是大于 2 的,故我们想用它来支付掉均摊代价

c^O(size(u))Δ(u)2α1O(size(u))(2α1)size(u)2α1=O(1)

最终得到重构的均摊代价是 O(1) 的。

接下来考虑分析插入,维护 α 平衡的情况下,其实际代价是树高 h=O(lgn),插入一个点会使一条链上的 Δ 均增或减 1,而这个增量也不会超过树高 h

c^=h+ΔΦ(T)h+h2α1=(1+12α1)h=O(lgn)

综上我们这样维护替罪羊树:如普通二叉搜索树的方式一样插入查询,插入完成时检查是否存在点不满足 α 平衡,若存在则找到深度最低的不平衡点再将以其为根的子树进行重构,这样可以保证在插入和查询的时候整棵树是 α 平衡的。根据上面的分析,所有的操作都将在 O(lgn) 的均摊效率下运行。

posted @   yukari1735  阅读(113)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示