LinkedList的本质是一个双向链表,这是结构
Node<E> node(
int
index
) {
// assert isElementIndex(index);
if
(
index
< (
size
>> 1)) {
Node<E>
x
=
first
;
for
(
int
i
= 0;
i
<
index
;
i
++)
x
=
x
.
next
;
return
x
;
}
else
{
Node<E>
x
=
last
;
for
(
int
i
=
size
- 1;
i
>
index
;
i
--)
x
=
x
.
prev
;
return
x
;
}
}
//根据元素位置获取元素
Node<E> node(int index) {
if
(
index
< (
size
>> 1)) {
Node<E>
x
=
first
;
for
(
int
i
= 0;
i
<
index
;
i
++)
x
=
x
.
next
;
return
x
;
}
else
{
Node<E>
x
=
last
;
for
(
int
i
=
size
- 1;
i
>
index
;
i
--)
x
=
x
.
prev
;
return
x
;
}
}
LinkedList 特点
-
双向链表实现
-
元素是有序的,输出顺序与输入顺序一致
-
允许元素为 null
-
和 ArrayList 一样,不是同步容器
并发访问注意事项
linkedList 和 ArrayList 一样,不是同步容器。所以需要外部做同步操作,或者直接用
Collections.synchronizedList
方法包一下,最好在创建时就
包
一下:
List list = Collections.synchronizedList(new LinkedList(...));
LinkedList 的迭代器都是 fail-fast 的: 如果在并发环境下,其他线程使用迭代器以外的方法修改数据,会导致 ConcurrentModificationException.
LinkedList和ArrayList的对比
1、顺序插入速度ArrayList会比较快,因为ArrayList是基于数组实现的,数组是事先new好的,只要往指定位置塞一个数据就好了;LinkedList则不同,每次顺序插入的时候LinkedList将new一个对象出来,如果对象比较大,那么new的时间势必会长一点,再加上一些引用赋值的操作,所以顺序插入LinkedList必然慢于ArrayList
2、基于上一点,因为LinkedList里面不仅维护了待插入的元素,还维护了Node的前置
Node
和后继
Node
,如果一个LinkedList中的
Node
非常多,那么LinkedList将比ArrayList更耗费一些内存
3、ArrayList使用for循环遍历快,因为是通过数组索引直接遍历,每次get的时间复杂度为O(1)
LinkedList使用foreach循环遍历快,因为使用普通for循环会每次从前一个节点拿后一个节点地址,相当于从头遍历一遍,每次get的时间复杂度为O(N)
4、有些说法认为LinkedList做插入和删除更快,这种说法其实是不准确的:
(1)LinkedList做插入、删除的时候,慢在寻址,快在只需要改变前后Entry的引用地址
(2)ArrayList做插入、删除的时候,慢在数组元素的批量copy,快在寻址
所以,如果待插入、删除的元素是在数据结构的前半段尤其是非常靠前的位置的时候,LinkedList的效率将大大快过ArrayList,因为ArrayList将批量copy大量的元素;越往后,对于LinkedList来说,因为它是双向链表,所以在第2个元素后面插入一个数据和在倒数第2个元素后面插入一个元素在效率上基本没有差别,但是ArrayList由于要批量copy的元素越来越少,操作速度必然追上乃至超过LinkedList
。
从这个分析看出,如果你十分确定你插入、删除的元素是在前半段,那么就使用LinkedList;如果你十分确定你删除、删除的元素在比较靠后的位置,那么可以考虑使用ArrayList。如果你不能确定你要做的插入、删除是在哪儿呢?那还是建议你使用LinkedList吧,因为一来LinkedList整体插入、删除的执行效率比较稳定,没有ArrayList这种越往后越快的情况;二来插入元素的时候,弄得不好ArrayList就要进行一次扩容,
ArrayList底层数组扩容是一个既消耗时间又消耗空间的操作。