简体   繁体   English

何时在 Java 中的 ArrayList 上使用 LinkedList?

[英]When to use LinkedList over ArrayList in Java?

I've always been one to simply use:我一直是一个简单使用的人:

List<String> names = new ArrayList<>();

I use the interface as the type name for portability , so that when I ask questions such as this, I can rework my code.我使用 interface 作为portability的类型名称,因此当我提出这样的问题时,我可以重新编写我的代码。

When should LinkedList be used over ArrayList and vice-versa?何时应在ArrayList上使用LinkedList ,反之亦然?

Summary ArrayList with ArrayDeque are preferable in many more use-cases than LinkedList .总结ArrayListArrayDeque更多用例中比LinkedList更可取。 If you're not sure — just start with ArrayList .如果您不确定 - 只需从ArrayList开始。


TLDR, in ArrayList accessing an element takes constant time [O(1)] and adding an element takes O(n) time [worst case]. TLDR,在ArrayList中访问一个元素需要常数时间 [O(1)],而添加一个元素需要 O(n) 时间[最坏情况]。 In LinkedList inserting an element takes O(n) time and accessing also takes O(n) time but LinkedList uses more memory than ArrayList .LinkedList中插入元素需要 O(n) 时间,访问也需要 O(n) 时间,但LinkedListArrayList使用更多内存。

LinkedList and ArrayList are two different implementations of the List interface. LinkedListArrayList是 List 接口的两种不同实现。 LinkedList implements it with a doubly-linked list. LinkedList使用双向链表实现它。 ArrayList implements it with a dynamically re-sizing array. ArrayList使用动态调整大小的数组来实现它。

As with standard linked list and array operations, the various methods will have different algorithmic runtimes.与标准链表和数组操作一样,各种方法将具有不同的算法运行时。

For LinkedList<E>对于LinkedList<E>

  • get(int index) is O(n) (with n/4 steps on average), but O(1) when index = 0 or index = list.size() - 1 (in this case, you can also use getFirst() and getLast() ). get(int index)O(n) (平均有n/4步),但是当index = 0index = list.size() - 1时为O(1) (在这种情况下,您也可以使用getFirst()getLast() )。 One of the main benefits of LinkedList<E> LinkedList<E>的主要好处之一
  • add(int index, E element) is O(n) (with n/4 steps on average), but O(1) when index = 0 or index = list.size() - 1 (in this case, you can also use addFirst() and addLast() / add() ). add(int index, E element)O(n) (平均有n/4步),但当index = 0index = list.size() - 1时为O(1) (在这种情况下,您也可以使用addFirst()addLast() / add() )。 One of the main benefits of LinkedList<E> LinkedList<E>的主要好处之一
  • remove(int index) is O(n) (with n/4 steps on average), but O(1) when index = 0 or index = list.size() - 1 (in this case, you can also use removeFirst() and removeLast() ). remove(int index)O(n) (平均有n/4步),但是当index = 0index = list.size() - 1时为O(1) (在这种情况下,您也可以使用removeFirst()removeLast() )。 One of the main benefits of LinkedList<E> LinkedList<E>的主要好处之一
  • Iterator.remove() is O(1) . Iterator.remove()O(1) One of the main benefits of LinkedList<E> LinkedList<E>的主要好处之一
  • ListIterator.add(E element) is O(1) . ListIterator.add(E element)O(1) One of the main benefits of LinkedList<E> LinkedList<E>的主要好处之一

Note: Many of the operations need n/4 steps on average, constant number of steps in the best case (eg index = 0), and n/2 steps in worst case (middle of list)注意:许多操作平均需要n/4步,最佳情况下的步数恒定(例如 index = 0),最坏情况下需要n/2步(列表中间)

For ArrayList<E>对于ArrayList<E>

  • get(int index) is O(1) . get(int index)O(1) Main benefit of ArrayList<E> ArrayList<E>的主要好处
  • add(E element) is O(1) amortized, but O(n) worst-case since the array must be resized and copied add(E element)O(1)摊销,但O(n)最坏情况,因为必须调整数组的大小和复制
  • add(int index, E element) is O(n) (with n/2 steps on average) add(int index, E element)O(n) (平均有n/2步)
  • remove(int index) is O(n) (with n/2 steps on average) remove(int index)O(n) (平均有n/2步)
  • Iterator.remove() is O(n) (with n/2 steps on average) Iterator.remove()O(n) (平均有n/2步)
  • ListIterator.add(E element) is O(n) (with n/2 steps on average) ListIterator.add(E element)O(n) (平均有n/2步)

Note: Many of the operations need n/2 steps on average, constant number of steps in the best case (end of list), n steps in the worst case (start of list)注意:许多操作平均需要n/2步,最佳情况下(列表末尾)的步数恒定,最坏情况下(列表开头)需要n

LinkedList<E> allows for constant-time insertions or removals using iterators , but only sequential access of elements. LinkedList<E>允许使用迭代器进行恒定时间的插入或删除,但只能顺序访问元素。 In other words, you can walk the list forwards or backwards, but finding a position in the list takes time proportional to the size of the list.换句话说,您可以向前或向后遍历列表,但在列表中查找位置所花费的时间与列表的大小成正比。 Javadoc says "operations that index into the list will traverse the list from the beginning or the end, whichever is closer" , so those methods are O(n) ( n/4 steps) on average, though O(1) for index = 0 . Javadoc 说“索引到列表中的操作将从开头或结尾遍历列表,以较近者为准” ,因此这些方法平均为O(n)n/4步),尽管O(1) for index = 0 .

ArrayList<E> , on the other hand, allow fast random read access, so you can grab any element in constant time.另一方面, ArrayList<E>允许快速随机读取访问,因此您可以在恒定时间内抓取任何元素。 But adding or removing from anywhere but the end requires shifting all the latter elements over, either to make an opening or fill the gap.但是从任何地方添加或删除,但最后需要将所有后面的元素转移过来,要么打开一个开口,要么填补空白。 Also, if you add more elements than the capacity of the underlying array, a new array (1.5 times the size) is allocated, and the old array is copied to the new one, so adding to an ArrayList is O(n) in the worst case but constant on average.另外,如果你添加的元素多于底层数组的容量,则会分配一个新数组(大小的 1.5 倍),并将旧数组复制到新数组中,因此添加到ArrayListO(n)最坏的情况,但平均保持不变。

So depending on the operations you intend to do, you should choose the implementations accordingly.因此,根据您打算执行的操作,您应该相应地选择实现。 Iterating over either kind of List is practically equally cheap.迭代任何一种 List 实际上同样便宜。 (Iterating over an ArrayList is technically faster, but unless you're doing something really performance-sensitive, you shouldn't worry about this -- they're both constants.) (在ArrayList上迭代在技术上更快,但除非你正在做一些对性能非常敏感的事情,否则你不应该担心这一点——它们都是常量。)

The main benefits of using a LinkedList arise when you re-use existing iterators to insert and remove elements.当您重新使用现有的迭代器来插入和删除元素时,使用LinkedList的主要好处就出现了。 These operations can then be done in O(1) by changing the list locally only.然后可以通过仅在本地更改列表在O(1)中完成这些操作。 In an array list, the remainder of the array needs to be moved (ie copied).在数组列表中,数组的其余部分需要移动(即复制)。 On the other side, seeking in a LinkedList means following the links in O(n) ( n/2 steps) for worst case, whereas in an ArrayList the desired position can be computed mathematically and accessed in O(1) .另一方面,在LinkedList中查找意味着在最坏的情况下遵循O(n)中的链接( n/2步),而在ArrayList中,可以通过数学方式计算所需的位置并在O(1)中访问。

Another benefit of using a LinkedList arises when you add or remove from the head of the list, since those operations are O(1) , while they are O(n) for ArrayList .当您从列表的头部添加或删除时,使用LinkedList的另一个好处会出现,因为这些操作是O(1) ,而对于ArrayListO(n) Note that ArrayDeque may be a good alternative to LinkedList for adding and removing from the head, but it is not a List .请注意, ArrayDeque可能是LinkedList的一个很好的替代方案,用于添加和删除头部,但它不是List

Also, if you have large lists, keep in mind that memory usage is also different.此外,如果您有大型列表,请记住内存使用量也不同。 Each element of a LinkedList has more overhead since pointers to the next and previous elements are also stored. LinkedList的每个元素都有更多开销,因为还存储了指向下一个和前一个元素的指针。 ArrayLists don't have this overhead. ArrayLists没有这种开销。 However, ArrayLists take up as much memory as is allocated for the capacity, regardless of whether elements have actually been added.但是, ArrayLists占用的内存与为容量分配的内存一样多,无论是否实际添加了元素。

The default initial capacity of an ArrayList is pretty small (10 from Java 1.4 - 1.8). ArrayList的默认初始容量非常小(Java 1.4 - 1.8 为 10)。 But since the underlying implementation is an array, the array must be resized if you add a lot of elements.但是由于底层实现是一个数组,如果添加很多元素,则必须调整数组的大小。 To avoid the high cost of resizing when you know you're going to add a lot of elements, construct the ArrayList with a higher initial capacity.当您知道要添加大量元素时,为避免调整大小的高成本,请构造具有更高初始容量的ArrayList

If the data structures perspective is used to understand the two structures, a LinkedList is basically a sequential data structure which contains a head Node.如果从数据结构的角度来理解这两种结构,LinkedList 基本上是一个包含头节点的顺序数据结构。 The Node is a wrapper for two components : a value of type T [accepted through generics] and another reference to the Node linked to it. Node 是两个组件的包装器:一个 T 类型的值 [通过泛型接受] 和另一个对链接到它的 Node 的引用。 So, we can assert it is a recursive data structure (a Node contains another Node which has another Node and so on...).所以,我们可以断言它是一个递归数据结构(一个节点包含另一个节点,另一个节点有另一个节点,依此类推......)。 Addition of elements takes linear time in LinkedList as stated above.如上所述,在 LinkedList 中添加元素需要线性时间。

An ArrayList is a growable array. ArrayList 是一个可增长的数组。 It is just like a regular array.它就像一个常规数组。 Under the hood, when an element is added, and the ArrayList is already full to capacity, it creates another array with a size which is greater than previous size.在幕后,当添加一个元素并且 ArrayList 已经满载时,它会创建另一个大小大于先前大小的数组。 The elements are then copied from previous array to new one and the elements that are to be added are also placed at the specified indices.然后将元素从先前的数组复制到新数组,并且要添加的元素也放置在指定的索引处。

Thus far, nobody seems to have addressed the memory footprint of each of these lists besides the general consensus that a LinkedList is "lots more" than an ArrayList so I did some number crunching to demonstrate exactly how much both lists take up for N null references.到目前为止,似乎没有人解决每个列表的内存占用问题,除了普遍认为LinkedListArrayList “多得多”,所以我做了一些数字运算来证明两个列表究竟占用了多少 N 个空引用.

Since references are either 32 or 64 bits (even when null) on their relative systems, I have included 4 sets of data for 32 and 64 bit LinkedLists and ArrayLists .由于引用在其相关系统上是 32 位或 64 位(即使为空),因此我为 32 位和 64 位LinkedListsArrayLists包含了 4 组数据。

Note: The sizes shown for the ArrayList lines are for trimmed lists - In practice, the capacity of the backing array in an ArrayList is generally larger than its current element count.注意:显示的ArrayList行的大小适用于修剪后的列表- 实际上, ArrayList中支持数组的容量通常大于其当前元素数。

Note 2: (thanks BeeOnRope) As CompressedOops is default now from mid JDK6 and up, the values below for 64-bit machines will basically match their 32-bit counterparts, unless of course you specifically turn it off.注意 2:(感谢 BeeOnRope)由于 CompressedOops 现在是 JDK6 中期及更高版本的默认值,因此以下 64 位机器的值将基本匹配它们的 32 位对应物,当然除非您特别将其关闭。


LinkedList 和 ArrayList 的图表 元素数量 x 字节


The result clearly shows that LinkedList is a whole lot more than ArrayList , especially with a very high element count.结果清楚地表明LinkedListArrayList多得多,尤其是在元素数量非常多的情况下。 If memory is a factor, steer clear of LinkedLists .如果内存是一个因素,请避开LinkedLists

The formulas I used follow, let me know if I have done anything wrong and I will fix it up.我使用的公式如下,如果我做错了什么,请告诉我,我会修复它。 'b' is either 4 or 8 for 32 or 64 bit systems, and 'n' is the number of elements.对于 32 位或 64 位系统,“b”是 4 或 8,“n”是元素的数量。 Note the reason for the mods is because all objects in java will take up a multiple of 8 bytes space regardless of whether it is all used or not.注意 mods 的原因是因为 java 中的所有对象无论是否全部使用都会占用 8 字节空间的倍数。

ArrayList:数组列表:

ArrayList object header + size integer + modCount integer + array reference + (array oject header + b * n) + MOD(array oject, 8) + MOD(ArrayList object, 8) == 8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8) + MOD(8 + 4 + 4 + b + (12 + b * n) + MOD(12 + b * n, 8), 8)

LinkedList:链表:

LinkedList object header + size integer + modCount integer + reference to header + reference to footer + (node object overhead + reference to previous element + reference to next element + reference to element) * n) + MOD(node object, 8) * n + MOD(LinkedList object, 8) == 8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n + MOD(8 + 4 + 4 + 2 * b + (8 + 3 * b) * n + MOD(8 + 3 * b, 8) * n, 8)

ArrayList is what you want. ArrayList是你想要的。 LinkedList is almost always a (performance) bug. LinkedList几乎总是一个(性能)错误。

Why LinkedList sucks:为什么LinkedList很烂:

  • It uses lots of small memory objects, and therefore impacts performance across the process.它使用大量的小内存对象,因此会影响整个进程的性能。
  • Lots of small objects are bad for cache-locality.许多小对象不利于缓存局部性。
  • Any indexed operation requires a traversal, ie has O(n) performance.任何索引操作都需要遍历,即具有 O(n) 性能。 This is not obvious in the source code, leading to algorithms O(n) slower than if ArrayList was used.这在源代码中并不明显,导致算法 O(n) 比使用ArrayList慢。
  • Getting good performance is tricky.获得良好的性能是棘手的。
  • Even when big-O performance is the same as ArrayList , it is probably going to be significantly slower anyway.即使 big-O 性能与ArrayList相同,它也可能会明显变慢。
  • It's jarring to see LinkedList in source because it is probably the wrong choice.在源代码中看到LinkedList令人震惊,因为它可能是错误的选择。
Algorithm           ArrayList   LinkedList
seek front            O(1)         O(1)
seek back             O(1)         O(1)
seek to index         O(1)         O(N)
insert at front       O(N)         O(1)
insert at back        O(1)         O(1)
insert after an item  O(N)         O(1)

Algorithms: Big-Oh Notation (archived) 算法:Big-Oh Notation (已归档)

ArrayLists are good for write-once-read-many or appenders, but bad at add/remove from the front or middle. ArrayLists 适用于一次写入多次读取或附加程序,但不适合从前面或中间添加/删除。

As someone who has been doing operational performance engineering on very large scale SOA web services for about a decade, I would prefer the behavior of LinkedList over ArrayList.作为一个在超大规模 SOA Web 服务上进行操作性能工程大约十年的人,我更喜欢 LinkedList 的行为而不是 ArrayList。 While the steady-state throughput of LinkedList is worse and therefore might lead to buying more hardware -- the behavior of ArrayList under pressure could lead to apps in a cluster expanding their arrays in near synchronicity and for large array sizes could lead to lack of responsiveness in the app and an outage, while under pressure, which is catastrophic behavior.虽然 LinkedList 的稳态吞吐量更差,因此可能会导致购买更多硬件 - ArrayList 在压力下的行为可能会导致集群中的应用程序以近乎同步的方式扩展其阵列,并且对于大阵列大小可能会导致缺乏响应能力在应用程序和中断,而在压力下,这是灾难性的行为。

Similarly, you can get better throughput in an app from the default throughput tenured garbage collector, but once you get java apps with 10GB heaps you can wind up locking up the app for 25 seconds during a Full GCs which causes timeouts and failures in SOA apps and blows your SLAs if it occurs too often.同样,您可以从默认吞吐量的终身垃圾收集器中获得更好的应用程序吞吐量,但是一旦您获得具有 10GB 堆的 Java 应用程序,您可能会在 Full GC 期间锁定应用程序 25 秒,这会导致 SOA 应用程序超时和失败如果它发生得太频繁,就会破坏你的 SLA。 Even though the CMS collector takes more resources and does not achieve the same raw throughput, it is a much better choice because it has more predictable and smaller latency.尽管 CMS 收集器占用更多资源并且无法达到相同的原始吞吐量,但它是一个更好的选择,因为它具有更高的可预测性和更小的延迟。

ArrayList is only a better choice for performance if all you mean by performance is throughput and you can ignore latency.如果您所说的性能是吞吐量并且您可以忽略延迟,那么 ArrayList 只是性能更好的选择。 In my experience at my job I cannot ignore worst-case latency.根据我的工作经验,我不能忽视最坏情况下的延迟。

Update (Aug 27, 2021 -- 10 years later): This answer (my most historically upvoted answer on SO as well) is very likely wrong (for reasons outlined in the comments below).更新(2021 年 8 月 27 日——10 年后):这个答案(我在 SO 上历史上最受欢迎的答案)很可能是错误的(原因在下面的评论中列出)。 I'd like to add that ArrayList will optimize for sequential reading of memory and minimize cache-line and TLB misses, etc. The copying overhead when the array grows past the bounds is likely inconsequential by comparison (and can be done by efficient CPU operations).我想补充一点,ArrayList 将优化内存的顺序读取并最大限度地减少缓存行和 TLB 未命中等。相比之下,当数组增长超过界限时的复制开销可能是无关紧要的(并且可以通过高效的 CPU 操作来完成)。 This answer is also probably getting worse over time given hardware trends.考虑到硬件趋势,随着时间的推移,这个答案也可能变得更糟。 The only situations where a LinkedList might make sense would be something highly contrived where you had thousands of Lists any one of which might grow to be GB-sized, but where no good guess could be made at allocation-time of the List and setting them all to GB-sized would blow up the heap. LinkedList 可能有意义的唯一情况是高度做作的事情,您有数千个列表,其中任何一个都可能增长到 GB 大小,但在分配列表和设置它们时无法做出好的猜测所有到 GB 大小的都会炸毁堆。 And if you found some problem like that, then it really does call for reengineering whatever your solution is (and I don't like to lightly suggest reengineering old code because I myself maintain piles and piles of old code, but that'd be a very good case of where the original design has simply run out of runway and does need to be chucked).如果你发现了这样的问题,那么无论你的解决方案是什么,它确实需要重新设计(我不喜欢轻易建议重新设计旧代码,因为我自己维护成堆的旧代码,但那将是一个非常好的案例,原始设计只是跑出了跑道,确实需要被淘汰)。 I'll still leave my decades-old poor opinion up there for you to read though.不过,我仍然会将我几十年前的糟糕观点留在那里供您阅读。 Simple, logical and pretty wrong.简单,合乎逻辑而且非常错误。

Yeah, I know, this is an ancient question, but I'll throw in my two cents:是的,我知道,这是一个古老的问题,但我会投入两分钱:

LinkedList is almost always the wrong choice, performance-wise. LinkedList 在性能方面几乎总是错误的选择。 There are some very specific algorithms where a LinkedList is called for, but those are very, very rare and the algorithm will usually specifically depend on LinkedList's ability to insert and delete elements in the middle of the list relatively quickly, once you've navigated there with a ListIterator.有一些非常特殊的算法需要 LinkedList,但这些算法非常非常罕见,并且该算法通常特别依赖于 LinkedList 在列表中间相对快速地插入和删除元素的能力,一旦你导航到那里使用 ListIterator。

There is one common use case in which LinkedList outperforms ArrayList: that of a queue. LinkedList 优于 ArrayList 的一个常见用例是:队列。 However, if your goal is performance, instead of LinkedList you should also consider using an ArrayBlockingQueue (if you can determine an upper bound on your queue size ahead of time, and can afford to allocate all the memory up front), or this CircularArrayList implementation .但是,如果您的目标是性能,而不是 LinkedList,您还应该考虑使用 ArrayBlockingQueue (如果您可以提前确定队列大小的上限,并且可以预先分配所有内存),或者这个CircularArrayList 实现. (Yes, it's from 2001, so you'll need to generify it, but I got comparable performance ratios to what's quoted in the article just now in a recent JVM) (是的,它是从 2001 年开始的,因此您需要对其进行泛化,但我得到的性能比与刚刚在最近的 JVM 中引用的文章中的内容相当)

Joshua Bloch, the author of LinkedList: LinkedList 的作者 Joshua Bloch:

Does anyone actually use LinkedList?有人真的使用 LinkedList 吗? I wrote it, and I never use it.我写了它,我从不使用它。

Link: https://twitter.com/joshbloch/status/583813919019573248链接: https ://twitter.com/joshbloch/status/583813919019573248

I'm sorry for the answer not being as informative as the other answers, but I thought it would be the most self-explanatory if not revealing.我很抱歉这个答案没有像其他答案那样信息丰富,但我认为如果不透露的话,这将是最不言自明的。

It's an efficiency question.这是一个效率问题。 LinkedList is fast for adding and deleting elements, but slow to access a specific element. LinkedList添加和删除元素的速度很快,但访问特定元素的速度很慢。 ArrayList is fast for accessing a specific element but can be slow to add to either end, and especially slow to delete in the middle. ArrayList访问特定元素的速度很快,但添加到任一端可能会很慢,尤其是在中间删除很慢。

Array vs ArrayList vs LinkedList vs Vector goes more in depth, as does Linked List . Array vs ArrayList vs LinkedList vs Vector更深入, Linked List也是如此。

Correct or Incorrect: Please execute test locally and decide for yourself!正确或错误:请在本地执行测试并自行决定!

Edit/Remove is faster in LinkedList than ArrayList . LinkedList中的编辑/删除比ArrayList更快。

ArrayList , backed by Array , which needs to be double the size, is worse in large volume application. ArrayListArray支持,需要双倍大小,在大容量应用中效果更差。

Below is the unit test result for each operation.Timing is given in Nanoseconds.下面是每个操作的单元测试结果。时间以纳秒为单位。


Operation                       ArrayList                      LinkedList  

AddAll   (Insert)               101,16719                      2623,29291 

Add      (Insert-Sequentially)  152,46840                      966,62216

Add      (insert-randomly)      36527                          29193

remove   (Delete)               20,56,9095                     20,45,4904

contains (Search)               186,15,704                     189,64,981

Here's the code:这是代码:

import org.junit.Assert;
import org.junit.Test;

import java.util.*;

public class ArrayListVsLinkedList {
    private static final int MAX = 500000;
    String[] strings = maxArray();

    ////////////// ADD ALL ////////////////////////////////////////
    @Test
    public void arrayListAddAll() {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX);

        watch.start();
        arrayList.addAll(stringList);
        watch.totalTime("Array List addAll() = ");//101,16719 Nanoseconds
    }

    @Test
    public void linkedListAddAll() throws Exception {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);

        watch.start();
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(stringList);
        watch.totalTime("Linked List addAll() = ");  //2623,29291 Nanoseconds
    }

    //Note: ArrayList is 26 time faster here than LinkedList for addAll()

    ///////////////// INSERT /////////////////////////////////////////////
    @Test
    public void arrayListAdd() {
        Watch watch = new Watch();
        List<String> arrayList = new ArrayList<String>(MAX);

        watch.start();
        for (String string : strings)
            arrayList.add(string);
        watch.totalTime("Array List add() = ");//152,46840 Nanoseconds
    }

    @Test
    public void linkedListAdd() {
        Watch watch = new Watch();

        List<String> linkedList = new LinkedList<String>();
        watch.start();
        for (String string : strings)
            linkedList.add(string);
        watch.totalTime("Linked List add() = ");  //966,62216 Nanoseconds
    }

    //Note: ArrayList is 9 times faster than LinkedList for add sequentially

    /////////////////// INSERT IN BETWEEN ///////////////////////////////////////

    @Test
    public void arrayListInsertOne() {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX + MAX / 10);
        arrayList.addAll(stringList);

        String insertString0 = getString(true, MAX / 2 + 10);
        String insertString1 = getString(true, MAX / 2 + 20);
        String insertString2 = getString(true, MAX / 2 + 30);
        String insertString3 = getString(true, MAX / 2 + 40);

        watch.start();

        arrayList.add(insertString0);
        arrayList.add(insertString1);
        arrayList.add(insertString2);
        arrayList.add(insertString3);

        watch.totalTime("Array List add() = ");//36527
    }

    @Test
    public void linkedListInsertOne() {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(stringList);

        String insertString0 = getString(true, MAX / 2 + 10);
        String insertString1 = getString(true, MAX / 2 + 20);
        String insertString2 = getString(true, MAX / 2 + 30);
        String insertString3 = getString(true, MAX / 2 + 40);

        watch.start();

        linkedList.add(insertString0);
        linkedList.add(insertString1);
        linkedList.add(insertString2);
        linkedList.add(insertString3);

        watch.totalTime("Linked List add = ");//29193
    }


    //Note: LinkedList is 3000 nanosecond faster than ArrayList for insert randomly.

    ////////////////// DELETE //////////////////////////////////////////////////////
    @Test
    public void arrayListRemove() throws Exception {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX);

        arrayList.addAll(stringList);
        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        arrayList.remove(searchString0);
        arrayList.remove(searchString1);
        watch.totalTime("Array List remove() = ");//20,56,9095 Nanoseconds
    }

    @Test
    public void linkedListRemove() throws Exception {
        Watch watch = new Watch();
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(Arrays.asList(strings));

        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        linkedList.remove(searchString0);
        linkedList.remove(searchString1);
        watch.totalTime("Linked List remove = ");//20,45,4904 Nanoseconds
    }

    //Note: LinkedList is 10 millisecond faster than ArrayList while removing item.

    ///////////////////// SEARCH ///////////////////////////////////////////
    @Test
    public void arrayListSearch() throws Exception {
        Watch watch = new Watch();
        List<String> stringList = Arrays.asList(strings);
        List<String> arrayList = new ArrayList<String>(MAX);

        arrayList.addAll(stringList);
        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        arrayList.contains(searchString0);
        arrayList.contains(searchString1);
        watch.totalTime("Array List addAll() time = ");//186,15,704
    }

    @Test
    public void linkedListSearch() throws Exception {
        Watch watch = new Watch();
        List<String> linkedList = new LinkedList<String>();
        linkedList.addAll(Arrays.asList(strings));

        String searchString0 = getString(true, MAX / 2 + 10);
        String searchString1 = getString(true, MAX / 2 + 20);

        watch.start();
        linkedList.contains(searchString0);
        linkedList.contains(searchString1);
        watch.totalTime("Linked List addAll() time = ");//189,64,981
    }

    //Note: Linked List is 500 Milliseconds faster than ArrayList

    class Watch {
        private long startTime;
        private long endTime;

        public void start() {
            startTime = System.nanoTime();
        }

        private void stop() {
            endTime = System.nanoTime();
        }

        public void totalTime(String s) {
            stop();
            System.out.println(s + (endTime - startTime));
        }
    }


    private String[] maxArray() {
        String[] strings = new String[MAX];
        Boolean result = Boolean.TRUE;
        for (int i = 0; i < MAX; i++) {
            strings[i] = getString(result, i);
            result = !result;
        }
        return strings;
    }

    private String getString(Boolean result, int i) {
        return String.valueOf(result) + i + String.valueOf(!result);
    }
}

ArrayList is essentially an array. ArrayList本质上是一个数组。 LinkedList is implemented as a double linked list. LinkedList实现为双链表。

The get is pretty clear. get的很清楚。 O(1) for ArrayList , because ArrayList allow random access by using index. ArrayList ArrayList使用索引进行随机访问。 O(n) for LinkedList , because it needs to find the index first. LinkedList的 O(n) ,因为它需要先找到索引。 Note: there are different versions of add and remove .注意: addremove有不同的版本。

LinkedList is faster in add and remove, but slower in get. LinkedList的 add 和 remove 速度更快,但 get 速度较慢。 In brief, LinkedList should be preferred if:简而言之,如果出现以下情况,应该首选LinkedList

  1. there are no large number of random access of element没有大量随机访问元素
  2. there are a large number of add/remove operations有大量的添加/删除操作

=== ArrayList === ===数组列表 ===

  • add(E e)加(E e)
    • add at the end of ArrayList在 ArrayList 末尾添加
    • require memory resizing cost.需要调整内存大小的成本。
    • O(n) worst, O(1) amortized O(n) 最差,O(1) 摊销
  • add(int index, E element)添加(int索引,E元素)
    • add to a specific index position添加到特定的索引位置
    • require shifting & possible memory resizing cost需要转移和可能的内存调整成本
    • O(n)上)
  • remove(int index)删除(整数索引)
    • remove a specified element移除指定元素
    • require shifting & possible memory resizing cost需要转移和可能的内存调整成本
    • O(n)上)
  • remove(Object o)删除(对象o)
    • remove the first occurrence of the specified element from this list从此列表中删除第一次出现的指定元素
    • need to search the element first, and then shifting & possible memory resizing cost需要先搜索元素,然后转移和可能的内存调整成本
    • O(n)上)

=== LinkedList === ===链表===

  • add(E e)加(E e)

    • add to the end of the list添加到列表的末尾
    • O(1) O(1)
  • add(int index, E element)添加(int索引,E元素)

    • insert at specified position在指定位置插入
    • need to find the position first需要先找到位置
    • O(n)上)
  • remove()消除()
    • remove first element of the list删除列表的第一个元素
    • O(1) O(1)
  • remove(int index)删除(整数索引)
    • remove element with specified index移除指定索引的元素
    • need to find the element first需要先找到元素
    • O(n)上)
  • remove(Object o)删除(对象o)
    • remove the first occurrence of the specified element删除指定元素的第一次出现
    • need to find the element first需要先找到元素
    • O(n)上)

Here is a figure from programcreek.com ( add and remove are the first type, ie, add an element at the end of the list and remove the element at the specified position in the list.):这是来自programcreek.com的图( addremove是第一种类型,即在列表末尾添加一个元素并删除列表中指定位置的元素。):

在此处输入图像描述

TL;DR due to modern computer architecture, ArrayList will be significantly more efficient for nearly any possible use-case - and therefore LinkedList should be avoided except some very unique and extreme cases. TL;DR由于现代计算机体系结构, ArrayList对于几乎任何可能的用例都将显着提高效率——因此除了一些非常独特和极端的情况外,应避免使用LinkedList


In theory, LinkedList has an O(1) for the add(E element)理论上,LinkedList 对于add(E element)

Also adding an element in the mid of a list should be very efficient.此外,在列表中间添加一个元素应该非常有效。

Practice is very different, as LinkedList is a Cache Hostile Data structure.实践非常不同,因为 LinkedList 是一个Cache Hostile Data 结构。 From performance POV - there are very little cases where LinkedList could be better performing than the Cache-friendly ArrayList .从性能 POV 来看,很少有LinkedList缓存友好的ArrayList性能更好的情况。

Here are results of a benchmark testing inserting elements in random locations.以下是在随机位置插入元素的基准测试结果。 As you can see - the array list if much more efficient, although in theory each insert in the middle of the list will require "move" the n later elements of the array (lower values are better):如您所见 - 数组列表效率更高,尽管理论上列表中间的每个插入都需要“移动”数组的n 个后面的元素(较低的值更好):

在此处输入图像描述

Working on a later generation hardware (bigger, more efficient caches) - the results are even more conclusive:在下一代硬件上工作(更大、更高效的缓存)——结果更具决定性:

在此处输入图像描述

LinkedList takes much more time to accomplish the same job. LinkedList 需要更多的时间来完成同样的工作。 source Source Code source源代码

There are two main reasons for this:这有两个主要原因:

  1. Mainly - that the nodes of the LinkedList are scattered randomly across the memory.主要是- LinkedList的节点随机分散在内存中。 RAM ("Random Access Memory") isn't really random and blocks of memory need to be fetched to cache. RAM(“随机存取存储器”)并不是真正随机的,需要提取内存块进行缓存。 This operation takes time, and when such fetches happen frequently - the memory pages in the cache need to be replaced all the time -> Cache misses -> Cache is not efficient.这个操作需要时间,而且当这种抓取频繁发生时——缓存中的内存页需要一直被替换->缓存未命中->缓存效率不高。 ArrayList elements are stored on continuous memory - which is exactly what the modern CPU architecture is optimizing for. ArrayList元素存储在连续内存上——这正是现代 CPU 架构正在优化的目标。

  2. Secondary LinkedList required to hold back/forward pointers, which means 3 times the memory consumption per value stored compared to ArrayList .二级LinkedList需要保留后向/前向指针,这意味着与ArrayList相比,存储的每个值的内存消耗是 3 倍。

DynamicIntArray , btw, is a custom ArrayList implementation holding Int (primitive type) and not Objects - hence all data is really stored adjacently - hence even more efficient.顺便说一句, DynamicIntArray是一个自定义 ArrayList 实现,它持有Int (原始类型)而不是 Objects - 因此所有数据实际上都是相邻存储的 - 因此效率更高。

A key elements to remember is that the cost of fetching memory block, is more significant than the cost accessing a single memory cell.要记住的一个关键因素是,获取内存块的成本比访问单个内存单元的成本更重要。 That's why reader 1MB of sequential memory is up to x400 times faster than reading this amount of data from different blocks of memory:这就是为什么读取器 1MB 的顺序内存比从不同的内存块读取这么多的数据快 400 倍:

Latency Comparison Numbers (~2012)
----------------------------------
L1 cache reference                           0.5 ns
Branch mispredict                            5   ns
L2 cache reference                           7   ns                      14x L1 cache
Mutex lock/unlock                           25   ns
Main memory reference                      100   ns                      20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy             3,000   ns        3 us
Send 1K bytes over 1 Gbps network       10,000   ns       10 us
Read 4K randomly from SSD*             150,000   ns      150 us          ~1GB/sec SSD
Read 1 MB sequentially from memory     250,000   ns      250 us
Round trip within same datacenter      500,000   ns      500 us
Read 1 MB sequentially from SSD*     1,000,000   ns    1,000 us    1 ms  ~1GB/sec SSD, 4X memory
Disk seek                           10,000,000   ns   10,000 us   10 ms  20x datacenter roundtrip
Read 1 MB sequentially from disk    20,000,000   ns   20,000 us   20 ms  80x memory, 20X SSD
Send packet CA->Netherlands->CA    150,000,000   ns  150,000 us  150 ms

Source: Latency Numbers Every Programmer Should Know资料来源:每个程序员都应该知道的延迟数字

Just to make the point even clearer, please check the benchmark of adding elements to the beginning of the list.为了更清楚地说明这一点,请检查将元素添加到列表开头的基准。 This is a use-case where, in-theory, the LinkedList should really shine, and ArrayList should present poor or even worse-case results:这是一个用例,理论上, LinkedList应该真正发光,而ArrayList应该呈现较差甚至更坏的结果:

在此处输入图像描述

Note: this is a benchmark of the C++ Std lib, but my previous experience shown the C++ and Java results are very similar.注意:这是 C++ 标准库的基准测试,但我之前的经验表明 C++ 和 Java 的结果非常相似。 Source Code源代码

Copying a sequential bulk of memory is an operation optimized by the modern CPUs - changing theory and actually making, again, ArrayList / Vector much more efficient复制连续的大量内存是现代 CPU 优化的操作 - 改变理论并实际上再次使ArrayList / Vector更加高效


Credits: All benchmarks posted here are created by Kjell Hedström .致谢:此处发布的所有基准均由Kjell Hedström创建。 Even more data can be found on his blog更多数据可以在他的博客上找到

ArrayList is randomly accessible, while LinkedList is really cheap to expand and remove elements from. ArrayList可以随机访问,而LinkedList扩展和删除元素非常便宜。 For most cases, ArrayList is fine.大多数情况下, ArrayList都可以。

Unless you've created large lists and measured a bottleneck, you'll probably never need to worry about the difference.除非您创建了大型列表并测量了瓶颈,否则您可能永远不需要担心差异。

If your code has add(0) and remove(0) , use a LinkedList and it's prettier addFirst() and removeFirst() methods.如果您的代码有add(0)remove(0) ,请使用LinkedList和更漂亮的addFirst()removeFirst()方法。 Otherwise, use ArrayList .否则,使用ArrayList

And of course, Guava 's ImmutableList is your best friend.当然, GuavaImmutableList是你最好的朋友。

I usually use one over the other based on the time complexities of the operations that I'd perform on that particular List.我通常根据我在该特定列表上执行的操作的时间复杂性使用一个而不是另一个。

|---------------------|---------------------|--------------------|------------|
|      Operation      |     ArrayList       |     LinkedList     |   Winner   |
|---------------------|---------------------|--------------------|------------|
|     get(index)      |       O(1)          |         O(n)       | ArrayList  |
|                     |                     |  n/4 steps in avg  |            |
|---------------------|---------------------|--------------------|------------|
|      add(E)         |       O(1)          |         O(1)       | LinkedList |
|                     |---------------------|--------------------|            |
|                     | O(n) in worst case  |                    |            |
|---------------------|---------------------|--------------------|------------|
|    add(index, E)    |       O(n)          |         O(n)       | LinkedList |
|                     |     n/2 steps       |      n/4 steps     |            |
|                     |---------------------|--------------------|            |
|                     |                     |  O(1) if index = 0 |            |
|---------------------|---------------------|--------------------|------------|
|  remove(index, E)   |       O(n)          |         O(n)       | LinkedList |
|                     |---------------------|--------------------|            |
|                     |     n/2 steps       |      n/4 steps     |            |
|---------------------|---------------------|--------------------|------------|
|  Iterator.remove()  |       O(n)          |         O(1)       | LinkedList |
|  ListIterator.add() |                     |                    |            |
|---------------------|---------------------|--------------------|------------|


|--------------------------------------|-----------------------------------|
|              ArrayList               |            LinkedList             |
|--------------------------------------|-----------------------------------|
|     Allows fast read access          |   Retrieving element takes O(n)   |
|--------------------------------------|-----------------------------------|
|   Adding an element require shifting | o(1) [but traversing takes time]  |
|       all the later elements         |                                   |
|--------------------------------------|-----------------------------------|
|   To add more elements than capacity |
|    new array need to be allocated    |
|--------------------------------------|

Let's compare LinkedList and ArrayList wrt below parameters:让我们比较一下 LinkedList 和 ArrayList wrt 下面的参数:

1. Implementation一、实施

ArrayList is the resizable array implementation of list interface , while ArrayList是列表接口的可调整大小的数组实现,而

LinkedList is the Doubly-linked list implementation of the list interface. LinkedList是列表接口的双向链表实现。


2. Performance 2. 性能

  • get(int index) or search operation get(int index) 或搜索操作

    ArrayList get(int index) operation runs in constant time ie O(1) while ArrayList get(int index) 操作以恒定时间运行,即 O(1) 而

    LinkedList get(int index) operation run time is O(n) . LinkedList get(int index) 操作运行时间为 O(n) 。

    The reason behind ArrayList being faster than LinkedList is that ArrayList uses an index based system for its elements as it internally uses an array data structure, on the other hand, ArrayList比 LinkedList 快的原因是 ArrayList 对其元素使用基于索引的系统,因为它在内部使用数组数据结构,另一方面,

    LinkedList does not provide index-based access for its elements as it iterates either from the beginning or end (whichever is closer) to retrieve the node at the specified element index. LinkedList不为其元素提供基于索引的访问,因为它从开头或结尾(以较近者为准)进行迭代以检索指定元素索引处的节点。

  • insert() or add(Object) operation insert() 或 add(Object) 操作

    Insertions in LinkedList are generally fast as compare to ArrayList. LinkedList中的插入通常比 ArrayList 快。 In LinkedList adding or insertion is O(1) operation .在 LinkedList 添加或插入是 O(1) 操作。

    While in ArrayList , if the array is the full ie worst case, there is an extra cost of resizing array and copying elements to the new array, which makes runtime of add operation in ArrayList O(n), otherwise it is O(1).而在ArrayList中,如果数组是完整的,即最坏的情况,调整数组大小并将元素复制到新数组会产生额外的成本,这使得 ArrayList 中添加操作的运行时间为 O(n),否则为 O(1) .

  • remove(int) operation删除(int)操作

    Remove operation in LinkedList is generally the same as ArrayList ie O(n). LinkedList 中的删除操作一般与ArrayList 相同,即O(n)。

    In LinkedList , there are two overloaded remove methods.LinkedList中,有两个重载的 remove 方法。 one is remove() without any parameter which removes the head of the list and runs in constant time O(1).一种是不带任何参数的 remove(),它删除列表的头部并以恒定时间 O(1) 运行。 The other overloaded remove method in LinkedList is remove(int) or remove(Object) which removes the Object or int passed as a parameter. LinkedList 中另一个重载的删除方法是 remove(int) 或 remove(Object),它删除作为参数传递的 Object 或 int。 This method traverses the LinkedList until it found the Object and unlink it from the original list.此方法遍历 LinkedList 直到找到 Object 并将其从原始列表中取消链接。 Hence this method runtime is O(n).因此,此方法运行时间为 O(n)。

    While in ArrayList remove(int) method involves copying elements from the old array to new updated array, hence its runtime is O(n).而在ArrayList remove(int) 方法涉及将元素从旧数组复制到新的更新数组,因此它的运行时间是 O(n)。


3. Reverse Iterator 3. 反向迭代器

LinkedList can be iterated in reverse direction using descendingIterator() while LinkedList可以使用 descendingIterator() 反向迭代,而

there is no descendingIterator() in ArrayList , so we need to write our own code to iterate over the ArrayList in reverse direction. ArrayList中没有 descendingIterator(),因此我们需要编写自己的代码来反向迭代 ArrayList。


4. Initial Capacity 4. 初始容量

If the constructor is not overloaded, then ArrayList creates an empty list of initial capacity 10, while如果构造函数没有重载,则ArrayList创建一个初始容量为 10 的空列表,而

LinkedList only constructs the empty list without any initial capacity. LinkedList只构造空列表,没有任何初始容量。


5. Memory Overhead 5. 内存开销

Memory overhead in LinkedList is more as compared to ArrayList as a node in LinkedList needs to maintain the addresses of the next and previous node.与 ArrayList 相比, LinkedList中的内存开销更大,因为 LinkedList 中的节点需要维护下一个和前一个节点的地址。 While尽管

In ArrayList each index only holds the actual object(data).ArrayList中,每个索引只保存实际的对象(数据)。


Source 资源

I know this is an old post, but I honestly can't believe nobody mentioned that LinkedList implements Deque .我知道这是一篇旧帖子,但我真的不敢相信没有人提到LinkedList实现了Deque Just look at the methods in Deque (and Queue );只需查看Deque (和Queue )中的方法; if you want a fair comparison, try running LinkedList against ArrayDeque and do a feature-for-feature comparison.如果您想要一个公平的比较,请尝试针对ArrayDeque运行LinkedList并进行功能比较。

Here is the Big-O notation in both ArrayList and LinkedList and also CopyOnWrite-ArrayList :这是ArrayListLinkedList以及CopyOnWrite-ArrayList中的 Big-O 符号:

ArrayList数组列表

get                 O(1)
add                 O(1)
contains            O(n)
next                O(1)
remove              O(n)
iterator.remove     O(n)

LinkedList链表

get                 O(n)
add                 O(1)
contains            O(n)
next                O(1)
remove              O(1)
iterator.remove     O(1)

CopyOnWrite-ArrayList CopyOnWrite-ArrayList

get                 O(1)
add                 O(n)
contains            O(n)
next                O(1)
remove              O(n)
iterator.remove     O(n)

Based on these you have to decide what to choose.基于这些,您必须决定选择什么。 :) :)

In addition to the other good arguments above, you should notice ArrayList implements RandomAccess interface, while LinkedList implements Queue .除了上面的其他好论点,您应该注意到ArrayList实现了RandomAccess接口,而LinkedList实现了Queue

So, somehow they address slightly different problems, with difference of efficiency and behavior (see their list of methods).因此,它们以某种方式解决了略有不同的问题,效率和行为有所不同(请参阅他们的方法列表)。

It depends upon what operations you will be doing more on the List.这取决于您将在列表中执行更多操作。

ArrayList is faster to access an indexed value. ArrayList访问索引值的速度更快。 It is much worse when inserting or deleting objects.插入或删除对象时情况更糟。

To find out more, read any article that talks about the difference between arrays and linked lists.要了解更多信息,请阅读任何有关数组和链表之间区别的文章。

An important feature of a linked list (which I didn't read in another answer) is the concatenation of two lists.链表的一个重要特征(我在另一个答案中没有读到)是两个列表的串联。 With an array this is O(n) (+ overhead of some reallocations) with a linked list this is only O(1) or O(2) ;-)对于数组,这是 O(n)(+ 一些重新分配的开销)对于链表,这只是 O(1) 或 O(2) ;-)

Important : For Java its LinkedList this is not true!重要提示:对于 Java,它的LinkedList是不正确的! See Is there a fast concat method for linked list in Java?请参阅Java中的链表是否有快速的连接方法?

An array list is essentially an array with methods to add items etc. (and you should use a generic list instead).数组列表本质上是一个具有添加项目等方法的数组(您应该改用通用列表)。 It is a collection of items which can be accessed through an indexer (for example [0]).它是可以通过索引器访问的项目集合(例如 [0])。 It implies a progression from one item to the next.它意味着从一个项目到下一个项目的进展。

A linked list specifies a progression from one item to the next (Item a -> item b).链表指定从一个项目到下一个项目的进展(项目 a -> 项目 b)。 You can get the same effect with an array list, but a linked list absolutely says what item is supposed to follow the previous one.您可以使用数组列表获得相同的效果,但链表绝对说明了应该在前一个之后的项目。

ArrayList and LinkedList have their own pros and cons. ArrayList 和 LinkedList 各有优缺点。

ArrayList uses contiguous memory address compared to LinkedList which uses pointers toward the next node. ArrayList 使用连续的内存地址,而 LinkedList 使用指向下一个节点的指针。 So when you want to look up an element in an ArrayList is faster than doing n iterations with LinkedList.因此,当您想在 ArrayList 中查找元素时,比使用 LinkedList 进行 n 次迭代要快。

On the other hand, insertion and deletion in a LinkedList are much easier because you just have to change the pointers whereas an ArrayList implies the use of shift operation for any insertion or deletion.另一方面,LinkedList 中的插入和删除要容易得多,因为您只需更改指针,而 ArrayList 意味着对任何插入或删除都使用移位操作。

If you have frequent retrieval operations in your app use an ArrayList.如果您的应用程序中有频繁的检索操作,请使用 ArrayList。 If you have frequent insertion and deletion use a LinkedList.如果您经常插入和删除,请使用 LinkedList。

1) Underlying Data Structure 1) 底层数据结构

The first difference between ArrayList and LinkedList comes with the fact that ArrayList is backed by Array while LinkedList is backed by LinkedList. ArrayList 和 LinkedList 之间的第一个区别在于 ArrayList 由 Array 支持,而 LinkedList 由 LinkedList 支持。 This will lead to further differences in performance.这将导致性能上的进一步差异。

2) LinkedList implements Deque 2) LinkedList 实现 Deque

Another difference between ArrayList and LinkedList is that apart from the List interface, LinkedList also implements Deque interface, which provides first in first out operations for add() and poll() and several other Deque functions. ArrayList 和 LinkedList 的另一个区别是除了 List 接口之外,LinkedList 还实现了 Deque 接口,该接口为add()poll()以及其他几个 Deque 函数提供先进先出操作。 3) Adding elements in ArrayList Adding element in ArrayList is O(1) operation if it doesn't trigger re-size of Array, in which case it becomes O(log(n)), On the other hand, appending an element in LinkedList is O(1) operation, as it doesn't require any navigation. 3)在ArrayList中添加元素 在ArrayList中添加元素如果不触发Array的re-size是O(1)操作,在这种情况下它变成O(log(n)),另一方面,在其中追加一个元素LinkedList 是 O(1) 操作,因为它不需要任何导航。

4) Removing an element from a position 4) 从一个位置移除一个元素

In order to remove an element from a particular index eg by calling remove(index) , ArrayList performs a copy operation which makes it close to O(n) while LinkedList needs to traverse to that point which also makes it O(n/2), as it can traverse from either direction based upon proximity.为了从特定索引中删除元素,例如通过调用remove(index) ,ArrayList 执行复制操作,使其接近 O(n) 而 LinkedList 需要遍历该点,这也使其成为 O(n/2) ,因为它可以根据接近度从任一方向遍历。

5) Iterating over ArrayList or LinkedList 5) 遍历 ArrayList 或 LinkedList

Iteration is the O(n) operation for both LinkedList and ArrayList where n is a number of an element.迭代是 LinkedList 和 ArrayList 的 O(n) 操作,其中 n 是元素的编号。

6) Retrieving element from a position 6) 从某个位置检索元素

The get(index) operation is O(1) in ArrayList while its O(n/2) in LinkedList, as it needs to traverse till that entry. get(index)操作在 ArrayList 中为 O(1),而在 LinkedList 中为 O(n/2),因为它需要遍历该条目。 Though, in Big O notation O(n/2) is just O(n) because we ignore constants there.不过,在大 O 表示法中,O(n/2) 只是 O(n),因为我们忽略了那里的常数。

7) Memory 7) 内存

LinkedList uses a wrapper object, Entry, which is a static nested class for storing data and two nodes next and previous while ArrayList just stores data in Array. LinkedList 使用一个包装对象 Entry,它是一个静态嵌套类,用于存储数据和两个节点 next 和 previous,而 ArrayList 只是将数据存储在 Array 中。

So memory requirement seems less in the case of ArrayList than LinkedList except for the case where Array performs the re-size operation when it copies content from one Array to another.因此,ArrayList 的内存需求似乎比 LinkedList 少,除了 Array 在将内容从一个 Array 复制到另一个 Array 时执行重新调整大小操作的情况。

If Array is large enough it may take a lot of memory at that point and trigger Garbage collection, which can slow response time.如果 Array 足够大,此时可能会占用大量内存并触发垃圾收集,这会减慢响应时间。

From all the above differences between ArrayList vs LinkedList, It looks ArrayList is the better choice than LinkedList in almost all cases, except when you do a frequent add() operation than remove() , or get() .从 ArrayList 与 LinkedList 之间的所有上述差异来看,看起来 ArrayList 在几乎所有情况下都是比 LinkedList 更好的选择,除非您执行频繁的add()操作而不是remove()get()

It's easier to modify a linked list than ArrayList, especially if you are adding or removing elements from start or end because linked list internally keeps references of those positions and they are accessible in O(1) time.修改链表比修改 ArrayList 更容易,尤其是当您从开始或结束添加或删除元素时,因为链表内部保留了这些位置的引用,并且它们可以在 O(1) 时间内访问。

In other words, you don't need to traverse through the linked list to reach the position where you want to add elements, in that case, addition becomes O(n) operation.换句话说,你不需要遍历链表到达你想要添加元素的位置,那样的话,加法就变成了O(n)的操作。 For example, inserting or deleting an element in the middle of a linked list.例如,在链表中间插入或删除一个元素。

In my opinion, use ArrayList over LinkedList for most of the practical purpose in Java.在我看来,对于 Java 中的大多数实际目的,使用 ArrayList 而不是 LinkedList。

Operation get(i) in ArrayList is faster than LinkedList, because: ArrayList 中的操作 get(i) 比 LinkedList 快,因为:
ArrayList: Resizable-array implementation of the List interface ArrayList: List 接口的 Resizable-array 实现
LinkedList: Doubly-linked list implementation of the List and Deque interfaces LinkedList: List 和 Deque 接口的双向链表实现

Operations that index into the list will traverse the list from the beginning or the end, whichever is closer to the specified index.索引到列表中的操作将从开头或结尾遍历列表,以更接近指定索引的为准。

ArrayList and LinkedList both implements List interface and their methods and results are almost identical. ArrayListLinkedList都实现了List interface ,它们的方法和结果几乎相同。 However there are few differences between them which make one better over another depending on the requirement.但是,它们之间几乎没有区别,这取决于要求,它们使一个比另一个更好。

ArrayList Vs LinkedList ArrayList 与 LinkedList

1) Search: ArrayList search operation is pretty fast compared to the LinkedList search operation. 1) Search: ArrayList搜索操作与LinkedList搜索操作相比非常快。 get(int index) in ArrayList gives the performance of O(1) while LinkedList performance is O(n) . ArrayList中的get(int index)给出了O(1)的性能,而LinkedList的性能是O(n)

Reason: ArrayList maintains index based system for its elements as it uses array data structure implicitly which makes it faster for searching an element in the list. Reason: ArrayList为其元素维护基于索引的系统,因为它隐式使用数组数据结构,这使得在列表中搜索元素的速度更快。 On the other side LinkedList implements doubly linked list which requires the traversal through all the elements for searching an element.另一方面, LinkedList实现了双向链表,它需要遍历所有元素以搜索元素。

2) Deletion: LinkedList remove operation gives O(1) performance while ArrayList gives variable performance: O(n) in worst case (while removing first element) and O(1) in best case (While removing last element). 2) Deletion: LinkedList删除操作提供O(1)性能,而ArrayList提供可变性能:最坏情况下为O(n) (删除第一个元素时),最佳情况下为O(1) (删除最后一个元素时)。

Conclusion: LinkedList element deletion is faster compared to ArrayList.结论:LinkedList 元素删除比 ArrayList 更快。

Reason: LinkedList's each element maintains two pointers (addresses) which points to the both neighbor elements in the list.原因:LinkedList 的每个元素都维护着两个指针(地址),它们指向列表中的两个相邻元素。 Hence removal only requires change in the pointer location in the two neighbor nodes (elements) of the node which is going to be removed.因此,删除只需要更改将要删除的节点的两个相邻节点(元素)中的指针位置。 While In ArrayList all the elements need to be shifted to fill out the space created by removed element.而在 ArrayList 中,所有元素都需要移动以填充已删除元素创建的空间。

3) Inserts Performance: LinkedList add method gives O(1) performance while ArrayList gives O(n) in worst case. 3) Inserts Performance: LinkedList add 方法在最坏的情况下给出O(1)性能,而ArrayList给出O(n) Reason is same as explained for remove.原因与删除的解释相同。

4) Memory Overhead: ArrayList maintains indexes and element data while LinkedList maintains element data and two pointers for neighbor nodes 4) Memory Overhead: ArrayList维护索引和元素数据,而LinkedList维护元素数据和相邻节点的两个指针

hence the memory consumption is high in LinkedList comparatively.因此,LinkedList 中的内存消耗相对较高。

There are few similarities between these classes which are as follows:这些类之间几乎没有相似之处,如下所示:

  • Both ArrayList and LinkedList are implementation of List interface. ArrayList 和 LinkedList 都是 List 接口的实现。
  • They both maintain the elements insertion order which means while displaying ArrayList and LinkedList elements the result set would be having the same order in which the elements got inserted into the List.它们都维护元素插入顺序,这意味着在显示 ArrayList 和 LinkedList 元素时,结果集将具有与元素插入列表相同的顺序。
  • Both these classes are non-synchronized and can be made synchronized explicitly by using Collections.synchronizedList method.这两个类都是非同步的,可以使用 Collections.synchronizedList 方法显式同步。
  • The iterator and listIterator returned by these classes are fail-fast (if list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException ).这些类返回的iteratorlistIteratorfail-fast (如果在创建迭代器后的任何时间对 list 进行结构修改,除了通过iterator's自己的 remove 或 add 方法之外的任何方式,迭代器将throw ConcurrentModificationException )。

When to use LinkedList and when to use ArrayList?什么时候用 LinkedList,什么时候用 ArrayList?

  • As explained above the insert and remove operations give good performance (O(1)) in LinkedList compared to ArrayList(O(n)) .如上所述,与ArrayList(O(n))相比, LinkedList中的插入和删除操作提供了良好的性能(O(1)) )。

    Hence if there is a requirement of frequent addition and deletion in application then LinkedList is a best choice.因此,如果应用中需要频繁的增删改查,那么LinkedList是最好的选择。

  • Search ( get method ) operations are fast in Arraylist (O(1)) but not in LinkedList (O(n))搜索( get method )操作在Arraylist (O(1))中很快,但在LinkedList (O(n))中则不然

    so If there are less add and remove operations and more search operations requirement, ArrayList would be your best bet.因此,如果添加和删除操作较少,搜索操作要求较多,ArrayList 将是您的最佳选择。

I have read the responses, but there is one scenario where I always use a LinkedList over an ArrayList that I want to share to hear opinions:我已经阅读了回复,但是在一种情况下,我总是在 ArrayList 上使用 LinkedList,我想分享以听取意见:

Every time I had a method that returns a list of data obtained from a DB I always use a LinkedList.每次我有一个方法返回从数据库获得的数据列表时,我总是使用 LinkedList。

My rationale was that because it is impossible to know exactly how many results am I getting, there will be not memory wasted (as in ArrayList with the difference between the capacity and actual number of elements), and there would be no time wasted trying to duplicate the capacity.我的理由是,因为不可能确切知道我得到了多少结果,所以不会浪费内存(就像 ArrayList 中的容量和实际元素数量之间的差异一样),并且不会浪费时间尝试复制容量。

As far a ArrayList, I agree that at least you should always use the constructor with the initial capacity, to minimize the duplication of the arrays as much as possible.就 ArrayList 而言,我同意至少您应该始终使用具有初始容量的构造函数,以尽可能减少数组的重复。

Both remove() and insert() have a runtime efficiency of O(n) for both ArrayLists and LinkedLists.对于 ArrayList 和 LinkedList, remove()insert()的运行时效率均为 O(n)。 However, the reason behind the linear processing time comes from two very different reasons:然而,线性处理时间背后的原因来自两个截然不同的原因:

In an ArrayList, you get to the element in O(1), but actually removing or inserting something makes it O(n) because all the following elements need to be changed.在 ArrayList 中,您可以在 O(1) 中找到元素,但实际上删除或插入某些东西会使它成为 O(n),因为需要更改以下所有元素。

In a LinkedList, it takes O(n) to actually get to the desired element, because we have to start at the very beginning until we reach the desired index.在 LinkedList 中,实际上需要 O(n) 才能到达所需的元素,因为我们必须从头开始,直到到达所需的索引。 Actually removing or inserting is constant, because we only have to change 1 reference for remove() and 2 references for insert() .实际上删除或插入是不变的,因为我们只需要更改remove()的 1 个引用和insert()的 2 个引用。

Which of the two is faster for inserting and removing depends on where it happens.两者中哪一个更快插入和删除取决于它发生的位置。 If we are closer to the beginning the LinkedList will be faster, because we have to go through relatively few elements.如果我们更接近开始,LinkedList 会更快,因为我们必须通过相对较少的元素。 If we are closer to the end an ArrayList will be faster, because we get there in constant time and only have to change the few remaining elements that follow it.如果我们更接近终点,ArrayList 会更快,因为我们在恒定时间内到达那里,只需要更改它后面的少数剩余元素。 When done precisely in the middle the LinkedList will be faster because going through n elements is quicker than moving n values.当恰好在中间完成时,LinkedList 会更快,因为遍历 n 个元素比移动 n 个值要快。

Bonus: While there is no way of making these two methods O(1) for an ArrayList, there actually is a way to do this in LinkedLists.奖励:虽然没有办法为 ArrayList 制作这两种方法 O(1),但实际上在 LinkedLists 中有一种方法可以做到这一点。 Let's say we want to go through the entire List removing and inserting elements on our way.假设我们要遍历整个 List 删除和插入元素。 Usually, you would start from the very beginning for each element using the LinkedList, we could also "save" the current element we're working on with an Iterator.通常,您将使用 LinkedList 从一开始就为每个元素开始,我们也可以使用迭代器“保存”我们正在处理的当前元素。 With the help of the Iterator, we get an O(1) efficiency for remove() and insert() when working in a LinkedList.在 Iterator 的帮助下,当在 LinkedList 中工作时, remove()insert() ) 的效率为 O(1)。 Making it the only performance benefit I'm aware of where a LinkedList is always better than an ArrayList.使它成为唯一的性能优势,我知道 LinkedList 总是比 ArrayList 更好。

One of the tests I saw on here only conducts the test once.我在这里看到的一项测试只进行一次测试。 But what I have noticed is that you need to run these tests many times and eventually their times will converge.但我注意到的是,您需要多次运行这些测试,最终它们的时间会收敛。 Basically the JVM needs to warm up.基本上,JVM 需要预热。 For my particular use case I needed to add/remove items to a list that grows to about 500 items.对于我的特定用例,我需要将项目添加/删除到一个增长到大约 500 个项目的列表中。 In my tests LinkedList came out faster, with LinkedList coming in around 50,000 NS and ArrayList coming in at around 90,000 NS... give or take.在我的测试中, LinkedList的输出速度更快, LinkedList大约有 50,000 NS,而ArrayList大约有 90,000 NS ...... See the code below.请参阅下面的代码。

public static void main(String[] args) {
    List<Long> times = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        times.add(doIt());
    }
    System.out.println("avg = " + (times.stream().mapToLong(x -> x).average()));
}

static long doIt() {
    long start = System.nanoTime();
    List<Object> list = new LinkedList<>();
    //uncomment line below to test with ArrayList
    //list = new ArrayList<>();
    for (int i = 0; i < 500; i++) {
        list.add(i);
    }

    Iterator it = list.iterator();
    while (it.hasNext()) {
        it.next();
        it.remove();
    }
    long end = System.nanoTime();
    long diff = end - start;
    //uncomment to see the JVM warmup and get faster for the first few iterations
    //System.out.println(diff)
    return diff;
}

ArrayList extends AbstractList and implements the List Interface. ArrayList 扩展了 AbstractList 并实现了 List 接口。 ArrayList is dynamic array. ArrayList 是动态数组。
It can be said that it was basically created to overcome the drawbacks of arrays可以说,它基本上是为了克服数组的弊端而创建的

The LinkedList class extends AbstractSequentialList and implements List,Deque, and Queue interface. LinkedList 类扩展了 AbstractSequentialList 并实现了 List、Deque 和 Queue 接口。
Performance表现
arraylist.get() is O(1) whereas linkedlist.get() is O(n) arraylist.get()是 O(1) 而linkedlist.get()是 O(n)
arraylist.add() is O(1) and linkedlist.add() is 0(1) arraylist.add()是 O(1), linkedlist.add()是 0(1)
arraylist.contains() is O(n) and linkedlist.contains() is O(n) arraylist.contains()是 O(n), linkedlist.contains()是 O(n)
arraylist.next() is O(1) and linkedlist.next() is O(1) arraylist.next()是 O(1), linkedlist.next()是 O(1)
arraylist.remove() is O(n) whereas linkedlist.remove() is O(1) arraylist.remove()是 O(n) 而linkedlist.remove()是 O(1)
In arraylist在数组列表中
iterator.remove() is O(n) iterator.remove()是 O(n)
whereas In linkedlist而在链表中
iterator.remove() is O(1) iterator.remove()是 O(1)

My rule of thumb is if I need a Collection (ie doesn't need to be a List ) then use ArrayList if you know the size in advance, or can know the size confidently, or know that it won't vary much.我的经验法则是,如果我需要一个Collection (即不需要是一个List ),那么如果您事先知道大小,或者可以自信地知道大小,或者知道它不会有太大变化,请使用ArrayList If you need random access (ie you use get(index) ) then avoid LinkedList .如果您需要随机访问(即使用get(index) ),请避免使用LinkedList Basically, use LinkedList only if you don't need index access and don't know the (approximate) size of the collection you're allocating.基本上,仅当您不需要索引访问并且不知道要分配的集合的(近似)大小时才使用LinkedList Also if you're going to be making lots of additions and removals (again through the Collection interface) then LinkedList may be preferable.此外,如果您要进行大量添加和删除(再次通过Collection接口),那么 LinkedList 可能更可取。

When should I use LinkedList ?我什么时候应该使用LinkedList When working with stacks mostly, or when working with buffers.主要使用堆栈或使用缓冲区时。 When should I use ArrayList ?我什么时候应该使用ArrayList Only when working with indexes, otherwise you can use HashTable with linked list, then you get:只有在使用索引时,否则您可以将 HashTable 与链表一起使用,然后您将获得:

Hash table + linked list哈希表+链表

  • Access by key O(1),通过密钥O(1) 访问,
  • Insert by key O(1),按键O(1) 插入,
  • Remove by key O(1)按键删除O(1)
  • and there is a trick to implement RemoveAll / SetAll with O(1) when using versioning在使用版本控制时,有一个技巧可以用 O(1) 实现 RemoveAll / SetAll

It seems like a good solution, and in most of the cases it is, how ever you should know: HashTable takes a lot of disc space, so when you need to manage 1,000,000 elements list it can become a thing that matters.这似乎是一个很好的解决方案,而且在大多数情况下,您应该知道:HashTable 占用大量磁盘空间,因此当您需要管理 1,000,000 个元素列表时,它可能变得很重要。 This can happen in server implementations, in clients it is rarely the case.这可能发生在服务器实现中,在客户端中很少发生。

Also take a look at Red-Black-Tree也看看红黑树

  • Random access Log(n),随机访问日志(n),
  • Insert Log(n),插入日志(n),
  • Remove Log(n)删除日志(n)

First of all use Vector instead ArrayList because you can overrite insureCapasity method , in ArrayList is private and add 1.5 size of current array https://docs.oracle.com/javase/8/docs/api/java/util/Vector.html#ensureCapacity-int-首先使用 Vector 代替 ArrayList 因为您可以覆盖 insureCapasity 方法,在 ArrayList 中是私有的并添加 1.5 大小的当前数组https://docs.oracle.com/javase/8/docs/api/java/util/Vector.html #ensureCapacity-int-

in many case it can be better that linkedList, the las has big advantage one you insert data with high freqency so size of you list changes very fast and you can't allocate size for number elements.在许多情况下,linkedList 可能会更好,las 具有很大的优势,即您可以插入高频数据,因此列表的大小变化非常快,并且您无法为数字元素分配大小。 In the theory you can get error like not "enough memory" but in modern computers you have 16G and swaping disk, so if you list is billoins elements you can fail, comparing 15-20 years ago.从理论上讲,您可能会遇到诸如“内存不足”之类的错误,但是在现代计算机中,您有 16G 和交换磁盘,因此与 15-20 年前相比,如果您列出的是 billoins 元素,您可能会失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM