【问题标题】:Does add method of LinkedList has better performance speed than the one of ArrayListLinkedList 的 add 方法是否比 ArrayList 的方法具有更好的性能速度
【发布时间】:2016-06-19 20:37:18
【问题描述】:

我正在为我的应用程序编写一个 java 程序,我担心速度性能。我做了一些基准测试,在我看来速度还不够好。我认为这与 arraylist 的 add ang get 方法有关,因为当我使用 jvm 并按快照时,它告诉我添加和获取 arraylist 方法需要更多的时间。

几年前我在使用 OCPJP 工具进行测试时读到,如果您想要进行大量添加和删除操作,请使用 LinkedList,但如果您想要快速迭代,请使用 ArrayList。换句话说,当你将使用 get 方法时使用 ArrayList,当你将使用 add 方法时使用 LinkedList,我已经做到了。

我不确定这是否正确?!

如果我必须坚持这一点,或者有任何其他方法可以提高我的表现,我希望有人给我一个建议。

【问题讨论】:

    标签: arraylist linked-list performance-testing


    【解决方案1】:

    我认为这与 arraylist 的 add ang get 方法有关,因为当我使用 jvm 并按快照时,它告诉我需要更多秒 add 和 get 方法的 arraylist

    听起来您已经使用分析器来检查实际问题是什么——这是第一个开始的地方!您是否能够发布可能暗示调用上下文的分析结果?正如in other questions 总结的那样,两种实现的某些操作的速度不同。如果您看到的调用确实是从 List 实现中的另一种方法调用的,那么您可能在追逐错误的东西(即在 ArrayList 的一端附近频繁调用 insert 会导致糟糕的性能)。

    一般性能将取决于实现,但是当我自己在实际条件下运行基准测试时,我发现 ArrayList-s 通常更适合我的用例如果能够在创建时适当调整它们的大小.

    LinkedList 可能会或可能不会为新节点保留预分配内存池,但是一旦池为空(如果存在),它将不得不分配更多 - 相对于 CPU 速度而言,这是一项昂贵的操作!也就是说,它只需要为一个节点分配至少足够的空间,然后将其附加到尾部;不会复制任何数据。

    ArrayList 暴露了它的实现部分,它预先分配了比底层数组实际需要的空间更多的空间,并随着元素的添加而增长。如果你初始化一个ArrayList,它就是defaults to an internal array size of 10 elements。问题是,当列表超出最初分配的大小时,它必须为旧的 新元素分配足够大的连续内存块,然后将旧数组中的元素复制到新的。

    简而言之,如果您:

    • 使用ArrayList
    • 不要指定initial capacity 来保证所有项目都适合
    • 继续使列表远远超出其原始容量

    复制项目时会产生大量开销。如果这是问题所在,从长远来看,成本应该在未来没有重新调整大小的情况下分摊……当然,除非你用新列表重复整个过程,而不是重新使用现在已有的原始列表长大了。

    对于迭代,数组是由一块连续的内存组成的。由于许多项目可能是相邻的,因此从主内存中获取数据的速度最终可能比LinkedList 中的节点快得多,LinkedList 中的节点可能会分散在各处,具体取决于内存中事物的布局方式。我强烈建议相信使用不同实现的分析器的数量并跟踪可能发生的情况。

    【讨论】:

    • 嗨,我使用 add 方法仅用于在列表中添加文件。然后我对 eacj 文件进行一些计算,并使用 get 方法获取每个文件,然后将其保存到新的数组列表中。所以基本上我有两种方法。一个用于添加所有文件,此方法返回一个链表,另一个用于对文件执行操作。但是在这种方法中,我需要从以前的方法中获取文件,所以在这里我使用 get 并且此方法返回一个数组列表,该数组列表的每个元素都是一个 2D 数组列表,它为每个文件保存操作。我不确定我是否必须使用数据结构
    • 只是为了确保我理解...第一种方法返回LinkedList,第二种方法在LinkedList 的循环中调用get(i)?如果是这样,那是你的问题。 get(i) 方法在 LinkedList 上很慢,因为它必须遍历 所有 个中间节点才能到达第整个列表,这是 O(n^2),或者对于列表中的 N 个项目,它需要 N*N 时间(sum[1..n] => n^2)。 ArrayList 只是计算 O(1)(恒定时间)访问的偏移量。您可以/将在数据结构课程中学习这种类型的分析。
    • 要解决此问题,请考虑使用Iterator 来迭代List ...这几乎总是您想要的,除非您明确使用ArrayListIterator 与“增强的 for 循环”一起使用 - for (File f : myFileList) { ... }
    • 对于 get(i) 否,我使用的是 ArrayList 而不是 LinkedList。我真正想了解的是arraylist的add(Object obj)的复杂度为O(1)或O(n),因为我读过不同的文章,他们说arraylist的add方法具有O(1)的复杂度摊销但我没有了解这里的摊销是什么意思
    • "amortized" 意味着从长远来看,当使用列表时,它是 O(1)。原因是如果列表不增长,则不需要调整大小。但是对于触发列表增长的单次插入,成本是 O(n),因为必须触及每个元素才能将完整复制到新分配的数组中。
    猜你喜欢
    • 1970-01-01
    • 2013-12-23
    • 2015-07-31
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    相关资源
    最近更新 更多