【问题标题】:ArrayList v.s. LinkedList - inserting timeArrayList 与LinkedList - 插入时间
【发布时间】:2012-08-17 22:54:17
【问题描述】:

当我跑步时(分别):

package containers;

import java.util.*;

    public static void main(String[] args) {

    List<Integer> arLst = new ArrayList<Integer>();
    List<Integer> lnLst = new LinkedList<Integer>();

    long start = System.currentTimeMillis();

    for (int i = 0; i < 10000000; i++) {
        arLst.add(i);
    }

    System.out.println("Array list: "+Long.toString(System.currentTimeMillis()-start));

    start = System.currentTimeMillis();

    for (int i = 0; i < 10000000; i++) {
        lnLst.add(i);
    }

    System.out.println("Linked list: "+Long.toString(System.currentTimeMillis()-start));
}

我得到大致相同的执行时间。 我知道 LinkedList 的添加时间应该更快。 我想知道为什么..(对于中间插入和最后一个元素来说,这是有道理的 - 因为数组知道在 O(1) 中插入的位置,不像 LinkedList 必须遍历整个列表,我记得)。

【问题讨论】:

  • 两个列表都是arraylist,你只添加到第一个。那是你的真实代码吗?假设这是一个错字,您应该在得出结论之前阅读this post
  • 为什么你的代码中的两个列表都是ArrayList
  • 我只看到ArrayList 而看不到LinkedList
  • 您为什么认为LinkedList 的添加时间应该更快?另外,必读:stackoverflow.com/questions/504103/…
  • 您应该测量列表创建后的时间。衡量创建它们需要多长时间是无关紧要的。

标签: java collections


【解决方案1】:

嗯…… 也许是这样:

List<Integer> lnLst = new ArrayList<>();

应该是这样的:

List<Integer> lnLst = new LinkedList<>();

我不明白你想测量什么。我认为您想衡量add 性能,然后您的代码应如下所示:

    public static void main(String[] args) {

        List<Integer> arLst = new ArrayList<Integer>();
        List<Integer> lnLst = new LinkedList<Integer>();

        long start = System.currentTimeMillis();

        for (int i = 0; i < 10000000; i++) {
            arLst.add(i);
        }

        System.out.println("Array list: "+Long.toString(System.currentTimeMillis()-start));

        start = System.currentTimeMillis();

        for (int i = 0; i < 10000000; i++) {
            lnLst.add(i);
        }

        System.out.println("Linked list: "+Long.toString(System.currentTimeMillis()-start));
    }

【讨论】:

  • 好了。这就是你的做法 OP。
  • 你自己有错字。第二个循环再次添加到arLst
  • 不是一个很好的基准 - 你应该预热 jvm 并监控垃圾收集以避免不一致的数字。
  • 谢谢,maba,已修复。是的,assylias,最好在每次测试之前执行完整的 GC,并且应该“预热”JIT。
  • 哦,哇,不知道我们在这里运行企业软件基准测试。 -_-
【解决方案2】:

两个列表都知道列表末尾的位置,因此插入时间几乎相同。我本来希望 LinkedList 会稍微慢一些,因为它会为每个元素创建一个节点并使用更多内存。

我明白了

TIntArrayList - 141 ms
ArrayList<Integer> - 810 ms
LinkedList<Integer> - 5190 ms.

TIntArrayList 不会更有效地使用缓存为每个元素创建对象。

【讨论】:

  • @assylias ArrayList 遭受了很大的打击,所以它的最坏情况不是很好,但平均而言它更快。
  • @assylias,它在最后摊销了 O(1) 加法,因此调整大小是无关紧要的,而且 ArrayList 很少增长不受约束。类似链表的结构(但不是树)在非并发设置中几乎没有任何好处。除非您非常清楚为什么需要链接结构,否则请使用 ArrayList/ArrayDeque。有一些极端情况,但它们通常不依赖于 java.util,但一个值得注意的例外是 LinkedHashMap(它是一个带索引的链表)
  • @assylias。作为旁注,大多数人没有意识到通过您自己的代码和尤其是通过 GC 遍历链接结构非常昂贵,因为它实际上会导致每次迭代的缓存未命中......
  • @bestsss 我没想到那样 - 有趣。
【解决方案3】:

您的两个列表都是ArrayLists...如果您将它们更改为LinkedList,您也不会注意到有很大的不同。以您的方式构建 ArrayList 可以摊销每次插入 O(1) 的复杂度。

【讨论】:

  • 更不用说他甚至没有在第二个列表中添加任何内容,并且同时对它们进行计时。
  • 是的,我什至没有注意到 :-)
【解决方案4】:

您的代码与您的解释不同。但是,这是您问题的答案:

ArrayList Vs LinkedList

【讨论】:

    【解决方案5】:

    ...因为数组知道在 O(1) 中插入的位置,不像 LinkedList 有 我记得要浏览整个列表)。

    这是不正确的。数组(不是 ArrayLists)没有固定的插入时间,Java 的 ArrayList 技术上也没有(对于 ArrayList,添加操作在 摊销的固定时间中运行)。 p>

    进一步,将元素插入到链表中是O(1)

    除了实现List接口,LinkedList类 提供统一命名的方法来获取、删除和插入元素 在列表的开头和结尾。

    如果您插入到排序列表中,复杂度变为O(N)

    【讨论】:

    • 如果您在 SortedLinked 列表中插入复杂度也是 O(n),因为您必须遍历列表,实际上它更糟糕,因为它是每次迭代的缓存未命中。数组支持的结构具有较低的内存占用和显着更快的遍历硬件如何工作的 b/c - 即缓存行和预取...... LinkedList 只是硬件不友好的结构。
    • @bestsss:虽然链表对缓存不友好,但我不同意缓存未命中会影响BigOh 时间复杂度。缓存未命中会导致惩罚:从内存(或磁盘,取决于我们谈论的缓存)读取块,这是一个恒定时间操作。当然,并非所有的恒定时间操作都是一样的。
    • 当然,大 O 保持不变,即使 O(16n) 也与 O(n) 相同。我的措辞很糟糕。 甚至更糟与大 O 无关,但与实际性能有关,类似于 在实践中变得更糟
    猜你喜欢
    • 2013-10-17
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    相关资源
    最近更新 更多