游戏动态

动态数组扩容时为什么复制成本不只看当前长度:机制分析第12例

2026-11-15

连续追加数据时,数组容量不足就可能需要分配更大的空间并复制旧内容。每次只增加很少容量,会频繁重复复制早已存在的元素;按比例增长通常会用更多空位换取较少复制。

先明确输入与规则

本例比较两种确定规则:容量不足时加上固定增量,或把原容量翻倍。开始容量相同,逐次追加一个元素,扩容时复制当前已有的全部元素,普通追加本身不计为复制。没有删除或缩容。

本例的独立记录

初始容量7,固定增长每次增加4,共追加33个元素。翻倍策略只在不足时乘二。

大小 | 固增容量 | 本次复制 | 累计复制 | 翻倍容量 | 本次复制 | 累计复制 1 | 7 | 0 | 0 | 7 | 0 | 0 2 | 7 | 0 | 0 | 7 | 0 | 0 3 | 7 | 0 | 0 | 7 | 0 | 0 4 | 7 | 0 | 0 | 7 | 0 | 0 5 | 7 | 0 | 0 | 7 | 0 | 0 6 | 7 | 0 | 0 | 7 | 0 | 0 7 | 7 | 0 | 0 | 7 | 0 | 0 8 | 11 | 7 | 7 | 14 | 7 | 7 9 | 11 | 0 | 7 | 14 | 0 | 7 10 | 11 | 0 | 7 | 14 | 0 | 7 11 | 11 | 0 | 7 | 14 | 0 | 7 12 | 15 | 11 | 18 | 14 | 0 | 7 13 | 15 | 0 | 18 | 14 | 0 | 7 14 | 15 | 0 | 18 | 14 | 0 | 7 15 | 15 | 0 | 18 | 28 | 14 | 21 16 | 19 | 15 | 33 | 28 | 0 | 21 17 | 19 | 0 | 33 | 28 | 0 | 21 18 | 19 | 0 | 33 | 28 | 0 | 21 19 | 19 | 0 | 33 | 28 | 0 | 21 20 | 23 | 19 | 52 | 28 | 0 | 21 21 | 23 | 0 | 52 | 28 | 0 | 21 22 | 23 | 0 | 52 | 28 | 0 | 21 23 | 23 | 0 | 52 | 28 | 0 | 21 24 | 27 | 23 | 75 | 28 | 0 | 21 25 | 27 | 0 | 75 | 28 | 0 | 21 26 | 27 | 0 | 75 | 28 | 0 | 21 27 | 27 | 0 | 75 | 28 | 0 | 21 28 | 31 | 27 | 102 | 28 | 0 | 21 29 | 31 | 0 | 102 | 56 | 28 | 49 30 | 31 | 0 | 102 | 56 | 0 | 49 31 | 31 | 0 | 102 | 56 | 0 | 49 32 | 35 | 31 | 133 | 56 | 0 | 49 33 | 35 | 0 | 133 | 56 | 0 | 49 最后空位:固定增长2,翻倍23。

记录中的编号只用来区分本例对象,不应与大小排名或另一组记录的身份混淆。先核对单位和边界,再跟随中间值检查结果。空结果、零值与尚未确定是不同状态;分数保留精确含义,显示小数只为方便阅读。

怎样复算

每次追加后大小不得超过容量;没有扩容时复制数为零。总复制数是每次扩容前大小的和,不是最终数组长度,也不是最终容量。扩出来但尚未使用的格子占空间,却不是需要从旧数组复制的有效元素。

把两条容量曲线和累计复制量并排记录,尤其观察刚跨过容量边界的那一步。一次追加触发大量复制,并不意味着此前每次追加都同样昂贵;反过来,单次追加很便宜也不能说明整段过程总成本低。

适用条件与限制

这是操作次数模型,不等同实际分配耗时;内存分配器、缓存和元素移动方式都会影响测量。翻倍也不一定符合所有设备的内存预算,本例只是让时间与额外空间之间的取舍可计算。

练习时可以一次只改变一个条件,比较差异从哪个步骤开始。若自己的结果不同,先核对是否采用同样的规则,再定位第一个不一致的中间状态,不要只修改最终答案。输入与运算过程需要一起保存,才能判断结论究竟适用于哪一个具体场景。