“边界在于摊还界的“总量”性质。摊还 $O(1)$ 不承诺任何单次操作快——动态数组的某次追加就是 $\Theta(n)$;它也不是概率语句,不提供尾界。需要逐操作延迟时,去摊还化会把一次大工…”
形式陈述
摊还分析保证一段操作序列的总成本,仍允许某次操作付出线性工作。去摊还化重新调度这些工作,让每次公开操作都只承担固定预算,同时保持中间状态可查询。它通常需要三份证明:迁移期间的访问仍正确,每次工作量有界,以及本轮迁移在下一轮启动之前结束。
一个完整模型:顺序动态数组
以下构造支持串行执行的
稳态维护动态数组
读操作从权威槽返回值,写操作只改权威槽;追加总写
每个合法公开操作先完成用户动作,再执行恰好
达到
越界读写在改变状态之前报告错误;新区分配失败也须在改变原逻辑序列前报告失败。下面的序列定理针对内存申请成功的合法操作。
正确性:权威槽归纳
不变量是:每个逻辑下标
稳态显然满足。启动时
微步复制的下标恰为
当
截止期:下次扩容前一定完成
从触发追加开始计数,设已经完成
本轮迁移最多需要
保证两轮不重叠。读写不消耗容量,却继续推进迁移,只会让完成时间提前。迁移任务始终是最初的
每次只搬一项其实也足够:第
直觉
摊还分析说“一整段操作付得起搬家费用”,去摊还化进一步安排“每次搬多少,以及搬家时到哪里找当前值”。前沿
两份物理副本并不要求双写。这里的串行次序保证复制总能读到未迁移位置的最新值,前沿推进后旧副本永久退出权威位置。困难在于规定清楚切换时刻,而不是让两块存储在每时每刻都完全相同。
图中的
例子与边界
一条含迁移期间读写的实际轨迹
初态容量与长度均为
| 操作 | 用户动作的位置与结果 | 随后复制的旧下标 | 结束状态 |
|---|---|---|---|
| 启动迁移,写 |
|||
| 从 |
|||
| 在稳态写 |
无 |
第三行更新尚未复制的槽,第五行最终数组为
若写操作错误地只更新未初始化的
图中的容量
分配、空间与真实时间
每次公开操作包含一个用户动作、至多两次槽复制,以及常数个元数据更新。若抽象模型把未初始化区块的保留与释放也计为
实际分配器可能初始化整块内存,元素复制可能触发复杂对象操作,释放可能调用析构或垃圾回收。此时应把这些成本另计,不能只凭“复制两槽”就声称真实执行时间有最坏常数界。惰性页映射也可能把成本推迟为页错误,不能自动提供硬实时保证。
迁移期间逻辑序列分布在两块区间,仍有最坏常数下标访问,但不再由单个连续存储区承载。需要持续暴露连续缓冲区地址的接口不能直接采用此构造。
哪些变化需要重新证明
删除、收缩、并发读写和后台迁移都超出上面的操作模型。它们可能改变重建期限、增加正在复制位置的竞争、或要求独立的内存回收协议。一个“加锁或加版本号”的建议本身既不构成完整正确性证明,也不提供等待时间上界。
更一般的数据结构还可能不断产生新的迁移任务。如果每步新增工作超过固定处理预算,积压会增长;这时必须重新比较任务到达率与处理率。本数组每轮任务数固定为
推论与应用
全局重建规定何时从活动元素恢复结构;一次性执行仍可能造成线性停顿。把它去摊还化,需要额外给出可增量执行的微步、过渡期访问规则和完成期限。本页的前沿是其中一种特定实现,其他结构可能需要双查、双写或更新日志,不能机械照搬。
确定性工作预算加确定性截止期才能给本页的逐操作最坏界。若重建规模只以高概率受控,则相应保证也只是高概率;若依赖后台线程,则还须加入调度假设。去摊还化改变的是算法的工作安排,不会凭空消除资源申请、竞争和回收成本。
参考资料
- Michael T. Goodrich, Daniel S. Hirschberg, Michael Mitzenmacher and Justin Thaler, Cache-Oblivious Dictionaries and Multimaps with Negligible Failure Probability, MedAlg 2012,作者稿 §4.1、p.11 的 crossover index 与每次访问复制两项。原文采用半满启动和访问前复制;本页对满载启动、操作后复制的顺序数组给出独立证明,不沿用其外围字典的概率保证。
- Mark H. Overmars, The Design of Dynamic Data Structures, Lecture Notes in Computer Science 156, Springer, 1983,动态重建与去摊还化的系统背景。