我编写了一个计算n个整数之和(随机生成)的程序,以便以一种我可以比较时间的方式测量计算ArrayList和LinkedList中所有值之和的时间(以纳秒为单位)。问题是,当我输入10 ^ 6(1,000,000)的大小进行计算时,它没有显示LinkedList计算所花费的时间,仅用于ArrayList。我有超过20分钟等待它显示,但仍然没有输出。但是,当我使用较小的数字大小如10 ^ 3或10 ^ 4时,它工作得很好。所以,我想知道在链接列表的大小方面是否存在限制。如果是这样,使用LinkedList的什么实现可以允许我计算大小为10 ^ 6的值的总和?
答案 0 :(得分:1)
让我猜猜你的代码是什么样的。
public class Test {
public static void main(String[] args) {
int LENGTH = 1000000;
List<Integer> list = new ArrayList<>();
for (int i = 0; i < LENGTH; i++) {
list.add((int) (100 * Math.random()));
}
// start timing
int sum = 0;
for (int i = 0; i < LENGTH; i++) {
sum += list.get(i);
}
// stop timing and report
}
}
那会很快。正在计时的部分可能不到十分之一秒。 (如果JVM已经正常“预热”,它会更快。)
但是,如果您只是将new ArrayList<>()
更改为new LinkedList<>()
...定时部分可能会减慢约100万。 (我可以高度自信地预测这一点,我会是正确的......)
但为什么?
这是因为get(int)
方法调用!
对于ArrayList
,调用get(i)
所需的时间是一个很小的常量。可能是10到20个硬件时钟周期,在典型系统上,每秒钟有数十亿个时钟周期。几纳秒。
对于LinkedList
get(i)
来电,需要从列表的开头开始并跳过i
个链接。一次一个。所花费的时间显然与i
的值成比例。
在您的测试用例中,i
的范围可达100万。因此,在LinkedList
版本中,您可以执行100万次循环迭代,其中每次迭代(平均)执行50万步。 (实际上,它可能是25万,因为LinkedList
是双重链接的,并且根据@makoto,get(i)
操作将从列表的开头或结尾遍历,以较近的{{1}为准}}。)
在技术方面,i
版测试程序的Big-O时间复杂度为ArrayList
,O(N)
版本为LinkedList
(即N平方。 ..)其中O(N^2)
是列表的长度。
有趣的是......如果你重写了这样的求和,性能问题会在N
案例中消失:
LinkedList
...因为现在您正在使用迭代器并调用 // start timing
int sum = 0;
for (Integer v : list) {
sum += v;
}
// stop timing and report
而不是next()
来获取值。