在Java中何时使用LinkedList而不是ArrayList?
内容来自 DOC https://q.houxu6.top/?s=在Java中何时使用LinkedList而不是ArrayList?
我总是这样使用:
List<String> names = new ArrayList<>();
我使用接口作为可移植性的类型名称,以便当我提出这样的问题时,我可以重新调整我的代码。
应该在什么时候使用 LinkedList
代替 ArrayList
,反之亦然?
总结:在许多用例中,与LinkedList
相比,ArrayList
和ArrayDeque
更喜欢使用ArrayList
。如果您不确定,请从ArrayList
开始。
TLDR,在ArrayList
中访问元素需要常数时间[O(1)],添加元素需要O(n)时间[最坏情况]。在LinkedList
中插入元素需要O(n)时间,访问也需要O(n)时间,但LinkedList
使用的内存比ArrayList
多。
LinkedList
和ArrayList
是List
接口的两种不同实现。LinkedList
使用双向链表实现。ArrayList
使用可动态调整大小的数组实现。
由于标准的链表和数组操作,各种方法将具有不同的算法运行时间。
对于LinkedList<E>
:
get(int index)
是O(n)(平均n/4步),但当index = 0
或index = list.size() - 1
时为O(1)(在这种情况下,您还可以使用getFirst()
和getLast()
)。LinkedList<E>
的主要优点是其中之一。add(int index, E element)
是O(n)(平均n/4步),但当index = 0
或index = list.size() - 1
时为O(1)(在这种情况下,您还可以使用addFirst()
和addLast()
/add()
)。LinkedList<E>
的主要优点是其中之一。remove(int index)
是O(n)(平均n/4步),但当index = 0
或index = list.size() - 1
时为O(1)(在这种情况下,您还可以使用removeFirst()
和removeLast()
)。LinkedList<E>
的主要优点是其中之一。Iterator.remove()
是O(1)。LinkedList<E>
的主要优点是其中之一。ListIterator.add(E element)
是O(1)。LinkedList<E>
的主要优点是其中之一。
注意:许多操作需要在平均情况下n/4步,在最好情况下(例如索引=0)为常数步数,在最坏情况下(列表中间)为n/2步数。
对于ArrayList<E>
:
get(int index)
是O(1)。ArrayList<E>
的主要优点是其中之一。add(E element)
是O(1),但最坏情况下为O(n),因为数组必须重新调整大小并复制。add(int index, E element)
是O(n)(平均n/2步)。remove(int index)
是O(n)(平均n/2步)。Iterator.remove()
是O(n)(平均n/2步)。ListIterator.add(E element)
是O(n)(平均n/2步)。
注意:许多操作需要在平均情况下n/2步,在最好情况下(列表末尾)为常数步数,在最坏情况下(列表开头)为n步数。
LinkedList<E>
允许使用迭代器以常数时间插入或删除元素,但只能顺序访问元素。换句话说,您可以向前或向后遍历列表,但查找列表中的位置需要花费与列表大小成比例的时间。Javadoc说"操作索引列表将从开头或结尾进行,哪个更近就选择哪个",因此这些方法在平均情况下是O(n)(n/4步),但在索引=0时为O(1)。
另一方面,ArrayList
允许快速随机读取访问,因此您可以在常数时间内获取任何元素。但是,除末尾外,从任何地方添加或删除都需要移动所有后面的元素,要么打开空间,要么填补缺口。此外,如果您添加的元素数量超过底层数组的容量,将分配一个新的数组(1.5倍的大小),并将旧数组复制到新数组中,因此在最坏情况下向ArrayList
添加是O(n),但平均值下是常数。
因此,根据您打算执行的操作,应相应地选择实现。遍历任何一种列表实际上成本差不多。 (在技术上,遍历ArrayList
更快,但除非您非常关注性能,否则不必担心这一点-它们都是常数。)
使用LinkedList
的主要好处在于,当您重用现有的迭代器来插入和删除元素时。这些操作可以通过仅局部更改列表在O(1)时间内完成。在数组列表中,数组的剩余部分需要移动(即复制)。另一方面,在LinkedList
中查找意味着按照O(n)(n/2步)跟踪链接,而在ArrayList
中,所需位置可以通过数学计算并在O(1)时间内访问。
当您从列表的开头添加或删除元素时,使用LinkedList
的另一个好处是,因为这些操作是O(1),而对于ArrayList
来说是O(n)。请注意,ArrayDeque
可能是LinkedList
的一个很好的替代选择,用于从开头添加和删除元素,但它不是List
。
此外,如果您有大型列表,请记住,内存使用也有所不同。由于还存储指向下一个和上一个元素的指针,因此LinkedList
的每个元素都有更多的开销。ArrayLists
没有这种开销。然而,ArrayLists
占用的内存与分配的容量相同,无论元素是否实际已添加。
ArrayList
的默认初始容量相当小(从Java 1.4到1.8的10个单位)。但由于底层实现是数组,因此如果要添加大量元素,则必须调整数组大小。为了避免在知道要添加大量元素时调整大小的高成本,请使用较高的初始容量构造ArrayList
。
如果从数据结构的角度来理解这两种结构,那么LinkedList
基本上是一个顺序数据结构,它包含一个头节点。节点是包装两个组件的包装器:一个通过泛型接受的类型T的值,以及另一个指向与其链接的节点的引用。因此,我们可以断言它是一种递归数据结构(一个节点包含另一个节点,该节点又有一个节点,依此类推...)。如上所述,LinkedList
中的元素添加需要线性时间。
ArrayList
是一种可增长的数组。它就像一个常规数组。在底层,当元素被添加并且ArrayList
已满时,它将创建一个比先前大得多的大小的新数组。然后,元素从先前的数组复制到新数组中,并且要添加的元素也放置在指定的索引处。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~