我注意到实现动态数组是非常常见的(尤其是在面试问题和家庭作业中);通常,我认为这个问题的措辞类似于:
实现一个阵列,当满时,的容量会翻倍
或者类似的东西。他们几乎总是(根据我的经验)明确地使用double这个词,而不是更通用的
实现一个阵列,在满时增加容量
我的问题是,为什么要加倍?我理解为什么使用常数值是个坏主意(多亏了这个问题),但似乎使用更大的倍数比双倍更有意义;为什么不将容量增加三倍、四倍或平方呢?
需要明确的是,我并不是在问如何将数组的容量加倍,而是在问为什么加倍是惯例。
是的,这是常见的做法。
加倍是管理内存的好方法。堆管理算法通常基于经典的伙伴系统,这是一种处理寻址和合并以及其他挑战的简单方法。知道这一点,在处理分配时最好坚持2的倍数(尽管有混合算法,如slab分配器,可以帮助处理碎片,所以使用倍数不像以前那么重要)。
克努思在他的一本书中提到了这一点,但我忘了书名。
请参阅http://en.wikipedia.org/wiki/Buddy_memory_allocation
将阵列大小增加一倍的另一个原因是增加成本。您不希望每个Add()操作都触发重新分配调用。如果你已经填满了N个空位,那么你很有可能需要N的倍数,不管怎样,历史是未来需求的一个很好的指标,所以对象需要"毕业"到下一个竞技场大小。通过加倍,重新分配的频率以对数方式下降(LogN)。加倍只是最方便的倍数(作为最小的整数倍,它比3*N或4*N更高效,而且它倾向于密切遵循堆内存管理模型)。
加倍背后的原因是它将重复地将元素追加到摊销的O(1)
运算中。换句话说,添加n
元素需要O(n)
时间。
更准确地说,增加任何乘法因子都可以实现这一点,但加倍是一种常见的选择。我看到了其他的选择,比如增加1.5
的因子。