使用LinkedList计算大数字的加法(Java)

时间:2014-10-18 00:51:26

标签: java linked-list

我编写了一个计算n个整数之和(随机生成)的程序,以便以一种我可以比较时间的方式测量计算ArrayList和LinkedList中所有值之和的时间(以纳秒为单位)。问题是,当我输入10 ^ 6(1,000,000)的大小进行计算时,它没有显示LinkedList计算所花费的时间,仅用于ArrayList。我有超过20分钟等待它显示,但仍然没有输出。但是,当我使用较小的数字大小如10 ^ 3或10 ^ 4时,它工作得很好。所以,我想知道在链接列表的大小方面是否存在限制。如果是这样,使用LinkedList的什么实现可以允许我计算大小为10 ^ 6的值的总和?

1 个答案:

答案 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时间复杂度为ArrayListO(N)版本为LinkedList(即N平方。 ..)其中O(N^2)是列表的长度。


有趣的是......如果你重写了这样的求和,性能问题会在N案例中消失:

LinkedList

...因为现在您正在使用迭代器并调用 // start timing int sum = 0; for (Integer v : list) { sum += v; } // stop timing and report 而不是next()来获取值。