Arrays 动态分配阵列的理想增长率是多少?
C++有std::vector,Java有ArrayList,许多其他语言都有自己的动态分配数组形式。当一个动态数组空间不足时,它会被重新分配到一个更大的区域中,旧值会被复制到新数组中。这种阵列性能的核心问题是阵列大小的增长速度。如果你总是长得足够大以适应当前的压力,那么你每次都会重新分配。因此,将数组大小加倍或乘以1.5倍是有意义的 有理想的生长因子吗?2倍?1.5倍?所谓理想,我指的是数学上合理的,最好的平衡性能和浪费的内存。我认识到,从理论上讲,考虑到您的应用程序可能具有任何潜在的推送分布,这在某种程度上取决于应用程序。但我很想知道是否有一个值“通常”是最好的,或者在某些严格的约束条件下被认为是最好的Arrays 动态分配阵列的理想增长率是多少?,arrays,math,vector,arraylist,dynamic-arrays,Arrays,Math,Vector,Arraylist,Dynamic Arrays,C++有std::vector,Java有ArrayList,许多其他语言都有自己的动态分配数组形式。当一个动态数组空间不足时,它会被重新分配到一个更大的区域中,旧值会被复制到新数组中。这种阵列性能的核心问题是阵列大小的增长速度。如果你总是长得足够大以适应当前的压力,那么你每次都会重新分配。因此,将数组大小加倍或乘以1.5倍是有意义的 有理想的生长因子吗?2倍?1.5倍?所谓理想,我指的是数学上合理的,最好的平衡性能和浪费的内存。我认识到,从理论上讲,考虑到您的应用程序可能具有任何潜在的推送分布
我听说某个地方有一篇关于这方面的论文,但我一直找不到。这将完全取决于用例。您是否更关心复制数据(和重新分配阵列)所浪费的时间,还是额外的内存?阵列将持续多长时间?如果它不会持续很长时间,使用更大的缓冲区可能是个好主意——惩罚是短期的。如果它将继续存在(例如,在Java中,进入越来越老的一代),这显然是一个更大的惩罚 没有所谓的“理想生长因子”,它不仅在理论上依赖于应用,而且绝对依赖于应用 2是一个非常常见的增长因子-我很确定这就是.NET中的
ArrayList
和List
所使用的编辑:正如Erich指出的,.NET中的字典使用“将大小加倍,然后增加到下一个素数”,这样散列值可以在存储桶之间合理分配。(我确信我最近看到的文档表明,素数实际上并不适合分发散列桶,但这是另一个答案的论据。)我同意Jon Skeet的观点,即使是我的theorycrafter朋友也坚持认为,当将因子设置为2x时,可以证明这是O(1)
在每台机器上,cpu时间和内存之间的比率是不同的,因此该系数也会有同样大的变化。如果您的机器具有千兆字节的ram,并且CPU速度较慢,那么将元素复制到新阵列的成本要比在速度较快的机器上高出很多,而速度较快的机器可能内存较少。这是一个理论上可以回答的问题,对于一个统一的计算机,在真实的场景中,它根本没有帮助你。 < P>我记得多年前阅读为什么1.5比两个更好,至少适用于C++(这可能不适用于托管语言,在那里运行时系统可以随意重新定位对象)。 理由是:
这要看情况而定。有些人通过分析常见的用例来找到最佳的数量
我以前见过使用1.5x2.0x phi x和2的幂。回答这样的问题时,一种方法是“作弊”,看看流行的库会做什么,假设广泛使用的库至少不会做可怕的事情 因此,快速检查一下,Ruby(1.9.1-p129)在附加到数组时似乎使用1.5x,Python(2.6.2)使用1.125x加上常量(in):
/*这与列表大小成比例的超额分配,腾出空间
*为了进一步的增长。这种过度分配是温和的,但也很严重
*足以在长期内产生线性时间摊销行为
*存在性能不佳的附件时的附件序列()
*系统realloc()。
*其生长模式为:0,4,8,16,25,35,46,58,72,88。。。
*/
新分配=(新闻大小>>3)+(新闻大小<9?3:6);
/*检查整数溢出*/
如果(新分配>PY大小\U最大值-新闻大小){
PyErr_nomery();
返回-1;
}否则{
新分配+=新闻大小;
}
newsize
以上是数组中的元素数。请注意,newsize
被添加到new\u allocated
,因此带有位移位和三元运算符的表达式实际上只是计算超额分配。如果您对数组长度有一个分布,并且您有一个实用函数,表示您多么喜欢浪费空间而不是浪费时间,然后,您可以选择最佳的调整大小(和初始大小)策略
之所以使用简单常数倍数,显然是因为每次追加都有固定的摊销时间。但这并不意味着你不能对小尺码使用不同(更大)的比例
在Scala中,您可以覆盖stan的loadFactor
/* This over-allocates proportional to the list size, making room
* for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
/* check for integer overflow */
if (new_allocated > PY_SIZE_MAX - newsize) {
PyErr_NoMemory();
return -1;
} else {
new_allocated += newsize;
}
T*x^n <= T + T*x + T*x^2 + ... + T*x^(n-2)
x^n <= 1 + x + x^2 + ... + x^(n-2)
x^3 <= 1 + x
n maximum-x (roughly)
3 1.3
4 1.4
5 1.53
6 1.57
7 1.59
22 1.61