参考:LinkedList 源码分析
在Java中,LinkedList
是一个双向链表,实现了List
和Deque
接口,可以被当作列表(List)、队列(Queue)或者双端队列(Deque)使用。它允许对元素进行高效的插入、删除操作,同时也支持随机访问。
不过,我们在项目中一般是不会使用到 LinkedList
的,需要用到 LinkedList
的场景几乎都可以使用 ArrayList
来代替,并且,性能通常会更好!就连 LinkedList
的作者约书亚 · 布洛克(Josh Bloch)自己都说从来不会使用 LinkedList
。
底层结构
LinkedList
底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。)
二者对比可以看出,双向循环链表的特点在于,最后一个节点的next指向第一个节点,而第一个节点的prev指向最后一个节点。
基本操作
增
- 添加到尾部(
addLast(e)
):O(1),因为只需要更新tail节点的引用。 - 添加到头部(
addFirst(e)
):O(1),同样只需要更新head节点的引用。 - 在指定位置添加(
add(int index, e)
):O(n),因为需要遍历链表到指定位置。
删
- 删除尾部元素(
removeLast()
):O(1),直接更新tail节点的引用。 - 删除头部元素(
removeFirst()
):O(1),直接更新head节点的引用。 - 删除指定位置的元素(
remove(int index)
):O(n),因为需要遍历到指定位置。 - 删除任意元素(
remove(Object o)
):O(n),需要遍历链表以查找对象。
改
- 修改指定位置的元素(
set(int index, e)
):O(n),需要先找到指定位置的元素,然后进行替换。
查
- 查询指定位置的元素(
get(int index)
):O(n),因为需要从头或尾部开始遍历到指定位置。 - 查找特定元素的索引(
indexOf(Object o)
):O(n),需要遍历链表以查找特定元素。
注意事项
- 由于
LinkedList
不是基于数组实现,所以它不保证在迭代过程中的快速随机访问。如果需要频繁地进行随机访问,ArrayList
可能是更好的选择。 - 在进行大量添加操作时,
LinkedList
的性能可能不如ArrayList
,因为数组的扩容操作相对较少,而链表需要频繁地更新节点的引用。 - 在需要频繁进行插入和删除操作的场景下,
LinkedList
是一个非常好的选择,尤其是在对列表中间元素进行操作时。