ruby数组内部

ruby数组内部,ruby,arrays,Ruby,Arrays,ruby阵列是如何在内部实现的(主要是在CRuby中,但欢迎提供任何其他信息) 它们是像C++向量一样可生长的数组还是基于列表?移位/取消移位和按索引访问元素的复杂性是什么?它们是可扩展的数组,可以“在末尾增长” shift是O(1),unshift是O(n),通过索引访问是O(1)。据我所知,这适用于所有ruby实现,但在MRI中肯定适用 更新:在最初编写这个答案之后,Ruby将进行unshift摊销O(1)。增强型阵列在中或之后,进行shift、unshift、push和pop所有O(1)或

ruby阵列是如何在内部实现的(主要是在CRuby中,但欢迎提供任何其他信息)


它们是像C++向量一样可生长的数组还是基于列表?移位/取消移位和按索引访问元素的复杂性是什么?

它们是可扩展的数组,可以“在末尾增长”

shift
O(1)
unshift
O(n)
,通过索引访问是
O(1)
。据我所知,这适用于所有ruby实现,但在MRI中肯定适用

更新:在最初编写这个答案之后,Ruby将进行
unshift
摊销
O(1)
。增强型阵列在中或之后,进行
shift
unshift
push
pop
所有
O(1)
或摊销
O(1)
在我的ruby1.9中,unshift是O(N^2)

$ /usr/bin/time ruby -e 'n=100000;l=[];(1..n).each{|i| l.push(i);}'
        0.03 real         0.02 user         0.00 sys
$ /usr/bin/time ruby -e 'n=100000;l=[];(1..n).each{|i| l.unshift(i);}'
        3.15 real         3.11 user         0.01 sys
$ /usr/bin/time ruby -e 'n=200000;l=[];(1..n).each{|i| l.unshift(i);}'
       12.96 real        12.85 user         0.03 sys
$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.3.0]

我不确定班次是否总是O(N)。如果我没记错的话,内存块的开头和第一个项的索引是分开跟踪的,因此可以通过增加第一个项的索引来执行O(1)移位。如果您没有进行任何移位,则取消移位仅为O(N)。@AShelly:您关于
shift
(虽然它实际上没有跟踪起始索引,而是使数组共享)的说法似乎是正确的,但是
Unshift
肯定是
O(N)
-它在数组上调用
memmove
,无论发生什么。取消移位似乎是O(1)在ruby 2.2中,只需签出SVN depo并阅读源代码。对于C程序员来说,实现并不困难。如果我错了,请纠正我,但这不表明取消移位具有二次时间复杂性吗?如果取消移位是线性的,当你把n从100000增加到200000时,你不认为所花的时间会翻倍吗。当n增加2倍时,完成算法所需的时间增加4倍。操作数与数据集的平方大小成正比。@louism2 right。。。我固定到了O(N^2),注意到unshift()在Ruby2中是O(N),在Ruby1.9中是O(N^2)。如果unshift是O(N),并且调用它N次,则需要O(N^2)时间。。另外,我想你想要一个趋势有两个以上的数据点,你想要的是
n=100000;b=1000;l=(1..n).到a;b、 times{l.unshift(1);}
(b代表基准,保持b不变,varry n)我在ruby-1.9.3-p551上得到了大约O(n),有趣的是,在ruby-2.2上得到了O(1)