内容来自 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
已满时,它将创建一个比先前大得多的大小的新数组。然后,元素从先前的数组复制到新数组中,并且要添加的元素也放置在指定的索引处。
- LinkedList ArrayList Javalinkedlist arraylist java linkedlist arraylist vector java linkedlist arraylist java p11 linkedlist arraylist linkedlist arraylist框架vector linkedlist arraylist vector list 相同点linkedlist arraylist vector linkedlist arraylist vector 异同linkedlist arraylist linkedlist arraylist源码