我一直是一个简单使用的人:

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

我使用接口作为可移植性的类型名称,这样当我问类似这样的问题时,我就可以修改代码。

LinkedList何时应用于ArrayList,反之亦然?


当前回答

ArrayList是可随机访问的,而LinkedList扩展和删除元素非常便宜。在大多数情况下,ArrayList都可以。

除非您创建了大量列表并测量了瓶颈,否则您可能永远不需要担心差异。

其他回答

ArrayList本质上是一个数组。LinkedList实现为双链接列表。

答案很清楚。O(1)表示ArrayList,因为ArrayList允许使用索引进行随机访问。O(n)表示LinkedList,因为它需要首先查找索引。注意:添加和删除有不同的版本。

LinkedList在添加和删除时速度更快,但在获取时速度较慢。简而言之,在以下情况下,应首选LinkedList:

元素没有大量的随机访问有大量的添加/删除操作

==阵列列表===

添加(E E)在ArrayList末尾添加需要内存大小调整成本。O(n)最差,O(1)摊销add(int索引,E元素)添加到特定索引位置需要移动和可能的内存调整成本O(n)删除(int索引)删除指定的元素需要移动和可能的内存调整成本O(n)删除(对象o)从此列表中删除第一个出现的指定元素需要先搜索元素,然后移动&可能的内存调整成本O(n)

==链接列表===

添加(E E)添加到列表末尾O(1)add(int索引,E元素)在指定位置插入需要先找到位置O(n)删除()删除列表的第一个元素O(1)删除(int索引)删除具有指定索引的元素需要先找到元素O(n)删除(对象o)删除指定元素的第一个引用需要先找到元素O(n)

这是programcreek.com中的一个图(add和remove是第一种类型,即在列表末尾添加元素,然后在列表中的指定位置删除元素):

到目前为止,除了人们普遍认为LinkedList比ArrayList“多得多”之外,似乎没有人解决这些列表中每一个的内存占用问题,所以我做了一些数字处理,以证明这两个列表对于N个空引用所占的空间。

由于引用在其相对系统上是32位或64位(即使为空),因此我为32位和64位LinkedList和ArrayList包含了4组数据。

注意:ArrayList行显示的大小是用于修剪列表的-实际上,ArrayList中的后备数组的容量通常大于其当前元素计数。

注2:(感谢BeeOnRope)由于压缩Oops现在是默认值,从JDK6中期开始,以下64位机器的值将基本上与32位机器的对应值相匹配,当然,除非您特意关闭它。



结果清楚地表明,LinkedList比ArrayList多得多,尤其是元素数非常高的情况。如果内存是一个因素,请避开LinkedList。

我使用的公式如下,如果我做错了什么,请告诉我,我会改正的对于32位或64位系统,b’是4或8,而n’是元素的数量。注意mods的原因是因为java中的所有对象都将占用8字节的倍数空间,而不管是否全部使用。

阵列列表:

ArrayList对象头+大小整数+modCount整数+数组引用+(数组项目头+b*n)+MOD

链接列表:

LinkedList对象标头+大小整数+modCount整数+对标头的引用+对页脚的引用+(节点对象开销+对上一元素的引用+下一元素的参考+对元素的引用)*n)+MOD(节点对象,8)*n+MOD, 8)

让我们将LinkedList和ArrayList与以下参数进行比较:

1.实施

ArrayList是列表接口的可调整大小的数组实现,而LinkedList是列表接口的双重链接列表实现。


2.性能

get(int索引)或搜索操作ArrayList get(int索引)操作在恒定时间内运行,即O(1)而LinkedList get(int索引)操作运行时间为O(n)。ArrayList比LinkedList更快的原因是ArrayList对其元素使用基于索引的系统,LinkedList不为其元素提供基于索引的访问,因为它从开始或结束(以较近者为准)迭代以检索指定元素索引处的节点。insert()或add(Object)操作与ArrayList相比,LinkedList中的插入通常很快。在LinkedList中,添加或插入是O(1)操作。在ArrayList中,如果数组已满(即最坏情况),则调整数组大小并将元素复制到新数组会产生额外的成本,这使得ArrayList的加法运算运行时为O(n),否则为O(1)。删除(int)操作LinkedList中的移除操作通常与ArrayList相同,即O(n)。在LinkedList中,有两个重载的移除方法。一个是remove(),没有任何参数,它会删除列表的头部,并在恒定时间O(1)内运行。LinkedList中的另一个重载remove方法是remove(int)或remove(Object),它删除作为参数传递的Object或int。此方法遍历LinkedList,直到找到Object并将其从原始列表中取消链接。因此,该方法运行时为O(n)。在ArrayList中,remove(int)方法涉及将元素从旧数组复制到新的更新数组,因此其运行时为O(n)。


3.反向迭代器

LinkedList可以使用descendingIterator()反向迭代,同时ArrayList中没有descendingIterator(),因此我们需要编写自己的代码以反向遍历ArrayList。


4.初始容量

如果构造函数没有重载,那么ArrayList将创建一个初始容量为10的空列表,而LinkedList只构建没有任何初始容量的空列表。


5.内存开销

与ArrayList相比,LinkedList中的内存开销更大,因为LinkedList的节点需要维护下一个和上一个节点的地址。虽然在ArrayList中,每个索引仅保存实际对象(数据)。


来源

我的经验法则是,如果我需要一个集合(即不需要是一个列表),那么如果你事先知道大小,或者可以自信地知道大小,或知道它不会有太大变化,那么就使用ArrayList。如果您需要随机访问(即使用get(index)),请避免LinkedList。基本上,只有当您不需要索引访问并且不知道正在分配的集合的(近似)大小时,才使用LinkedList。此外,如果您要进行大量添加和删除(再次通过Collection接口),则LinkedList可能更可取。

ArrayList和LinkedList各有利弊。

与使用指向下一个节点的指针的LinkedList相比,ArrayList使用连续内存地址。因此,当您想在ArrayList中查找元素时,比使用LinkedList进行n次迭代更快。

另一方面,LinkedList中的插入和删除要容易得多,因为您只需更改指针,而ArrayList意味着对任何插入或删除都使用移位操作。

如果您的应用程序中有频繁的检索操作,请使用ArrayList。如果频繁插入和删除,请使用LinkedList。