“考虑容量满时翻倍的动态数组。从容量 $1$ 开始连续追加 $n$ 个元素,新元素本身共写入 $n$ 次,当 $n\ge2$ 时,各次扩容搬迁的元素数恰为”
形式陈述
动态数组用一块连续的数组维护长度
按下标读取为
以初始容量
加上每次追加自身的一次写入,总工作量仍为线性。若支持自动收缩,收缩阈值必须低于扩张阈值,例如装载率降到
直觉
动态数组用空余空间购买增长余地。大多数追加只占用已经预留的下一个槽位,偶尔才整体搬家;昂贵搬迁不是消失了,而是由此前一长串便宜操作共同分摊。容量按常数因子增长的关键在于:每次搬迁后,新空位与已有元素同量级,所以在再次搬迁前必然发生足够多的新追加。
连续布局保留了普通数组的地址计算与缓存局部性,却也继承了它的限制。中间插入或删除会改变后缀元素的位置,通常仍需
例子与边界
从容量
若每次满时只把容量增加一格,第
扩容还会使指向旧存储区的地址、迭代器或引用失效;哪些引用保持有效取决于语言和容器契约。容量是实现状态,不等于可观察的逻辑长度,也不能把尚未初始化的槽位当成序列成员。
推论与应用
动态数组是向量、可变列表、字节缓冲区与许多哈希表桶数组的常见底层表示。它把
势能法可把空余容量或装载率偏离目标的程度编码成势,统一证明扩张与收缩的摊还界。工程实现还需考虑增长因子对空间与复制次数的取舍:因子较大减少搬迁,代价是更多闲置空间;因子接近
顺序数组去摊还化把一次整体复制分成固定预算的微步,按迁移前沿决定读写旧区或新区,并证明下一次扩容前完成。它在明确的分配成本模型下支持最坏常数的追加、读、写;迁移期间逻辑序列跨两块存储,因此不直接保留单一连续缓冲区接口。
参考资料
- Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms, 4th ed., MIT Press, 2022,§16.4, dynamic tables。
- Erik D. Demaine, MIT 6.046J Design and Analysis of Algorithms, amortized analysis of dynamic-table expansion and contraction, accessed 2026.