LinkedList是JDK提供的一个集合工具类。
LinkedList特点
- 底层数据结构为双向链表,查询慢增删快
- 元素可重复,值可为null
- 线程不安全
源码剖析
LinkedList使用的内部类Node,表示链表节点,比较简单
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
LinkedList实现双向链表所使用的两个变量
transient Node<E> first;
transient Node<E> last;
LinkedList添加节点相关方法
public boolean add(E e) {
linkLast(e);
return true;
}
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
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对象将prev指针当前last节点,并将last节点的next指针指向新创建的Node对象,所有没什么性能消耗。
第二个方法是往链表指定位置index插入元素,这时需要通过node方法遍历链表,找到当前链表index位置上的Node对象,并把元素插到当前index的Node对象前面。
第三个方法是遍历链表找到指定index位置的Node对象,可以看到如果index小于当前链表size的一半,则从前往后找,否则就从最后一个节点往前找。
同理可以看下LinkedList的get()相关方法。
经典面试题
问题一: 请问ArrayList和LinkedList的区别?
ArrayList的介绍可以查看小西之前发表的文章 ArrayList应该怎么用 。
这个问题的本质大体上是数据结构数组和链表的区别,但是回答的时候建议从以下两方面聊聊具体细节:
读数据:
ArrayList基本上快于LinkedList,但是从上面的node方法可以看出,如果是读取链表头部或者尾部附近元素的话,性能上LinkedList和ArrayList几乎差不多。
插入数据:
在尾部插入数据时,ArrayList和LinkedList差不多(ArrayList扩容时例外,但这个很少发生)。
在头部插入数据时,ArrayList性能最差,因为需要复制整个数据,LinkedList很快。
在中间插入元素时,ArrayList查询index位置很快,但是需要把index后面的元素做复制操作;LinkedList查询比较慢(offer方法),插入很快;但是LinkedList的offer方法性能还是要优于ArrayList的复制操作,所以该情况下面LinkedList性能较好。
删除数据:
大家可以想一想,看看源码,参考插入数据部分的逻辑。
同时还可以关注公众号“小西学JAVA”获取更多精彩文章。