前言
LinkedList和ArrayList有很大程度的相似,但却各有千秋,LinkedList没有容量的限制(只要内存足够大),LinkedList为双向链表,它也可以被当作堆栈、队列或双端队列进行操作。
源码解析
LinkedList类
LinkedList 是一个继承于AbstractSequentialLis并且实现了List 、Deque 、Cloneable、Serializable接口
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList属性
//元素个数
transient int size = 0;
//头结点
transient Node<E> first;
//尾结点
transient Node<E> last;
LinkedList构造器
//无参数构造,空集合
public LinkedList()
//初始化包含指定集合元素构造器
public LinkedList(Collection<? extends E> c)
LinkedList存储元素内部类
//链表使用内部类Node承载数据
private static class Node<E> {
//当前元素
E item;
//当前元素上一个Node
Node<E> next;
//当前元素下一个Node
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
LinkedList主要方法
向链表中添加数据 push
//添加元素
public void push(E e) {
addFirst(e);
}
//添加元素到链表的头部
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
//记录当前链表中头结点元素
final Node<E> f = first;
//构造新元素Node,并指定该Node的下一个元素为头结点
final Node<E> newNode = new Node<>(null, e, f);
//将头结点更新为新加入的节点
first = newNode;
if (f == null)
//如果当前链表中没有元素,那么首个元素即为头结点,也为末尾结点
last = newNode;
else
//将原头结点的上一个元素指向新元素
f.prev = newNode;
//元素个数加1
size++;
modCount++;
}
从链表取出数据 pop
//获取元素
public E pop() {
//返回链表头部元素并删除
return removeFirst();
}
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
//取出头部元素并返回
return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
//取出头部Node中的元素置为null并将next指向null,有助于垃圾回收
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null;
//将next置为头部Node
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
添加删除图解
LinkedList优缺点
- 优点:LinkedList实际上是通过双向链表去实现的,既然是双向链表,那么它的顺序访问会非常高效,并且没有容量限制
- 缺点:LinkedList随机访问比较低效,需要从头结点或者尾结点进行遍历,情况最坏时间复杂度为O(n)
总结
LinkedList很适合频繁顺序添加和删除的场景,对于大量数据的存储不需要连续的内存空间
(转载请注明出处)