LinkedList是一个双向链表的数据结构实现。java
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
这个类提供了一个List接口实现,为实现序列访问的数据存储结构提供了所须要的最小化接口实现。对于支持随机访问数据的List好比数组,应该优先使用AbstractList。node
一个有序的集合。这个接口能够精确控制每一个元素在列表中的位置插入。用户能够经过整数索引来访问元素(位置在列表中)。数组
一个有序的集合支持在头和尾进行插入和删除元素。deque是 double ended queue (双端队列)的缩写。
deque的大多实现元素数量是没有大小限制的。但这个接口支持容量限制。微信
public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
第一个是一个空的构造器,第二个构造器调用了addAll()方法。数据结构
在研究addAll()方法以前,咱们先来看一下几个重要的属性。源码分析
//容器的大小: transient int size = 0; //首节点: transient Node<E> first; //尾节点: transient Node<E> last; //节点数据结构 private static class Node<E> { E item;//节点的值 Node<E> next;//节点的下一个节点 若是等于null 则为尾节点 Node<E> prev;//节点的上一个节点,若是等于null则为首节点 Node(Node<E> prev, E element, Node<E> next) {//构造器 构造节点 this.item = element; this.next = next; this.prev = prev; } }
private void linkFirst(E e) { final Node<E> f = first;//得到第一个节点 final Node<E> newNode = new Node<>(null, e, f);//构造本次插入的首节点,以前的首节点做为下一个节点 first = newNode;//本次插入节点做为首节点 if (f == null)//若是首节点为空,则尾节点也为他 last = newNode; else f.prev = newNode;//不然,以前的首节点做为新节点的下一个节点 size++;//容器大小加一 modCount++;//修改次数加一 }
void linkLast(E e) { final Node<E> l = last;//获取尾节点 final Node<E> newNode = new Node<>(l, e, null);//构造新节点 last = newNode;//本次插入节点为尾节点 if (l == null)//若是尾节点为空 first = newNode;//则插入以前为空容器,首节点也为本次插入节点 else l.next = newNode;//不然本次插入节点为以前尾节点的下一个节点 size++;//容器大小加一 modCount++;//修改次数加一 }
//插入节点e ,在不为空的succ节点以前 void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev;//succ的前一个节点 final Node<E> newNode = new Node<>(pred, e, succ);//构造新节点插入succ以前 succ.prev = newNode;//succ的前一个节点为新构造的节点 if (pred == null)//若是succ的前一个节点为空,则本次插入节点将作为首节点 first = newNode; else pred.next = newNode;//不然新节点做为succ的上一个节点 size++;//容器大小加一 modCount++;//修改次数加一 }
private E unlinkFirst(Node<E> f) { // assert f == first && f != null; final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element; }
f.next 释放了内存,等待垃圾回收机制进行回收内存。this
//unlinkFirst方法被调用移除首节点 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); }
private E unlinkLast(Node<E> l) { // assert l == last && l != null; final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; } public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); }
public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; }
public boolean remove(Object o) { if (o == null) {//若是被移除元素为空 for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) {//判断节点的值是否为空 unlink(x);//移除元素 return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; }
public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; }
public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); }
public boolean offer(E e) { return add(e); }
从poll和offer方法能够看出Linked是一个FIFO先进先出队列(first input first output )spa
//使用二分法用索引查找元素 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; }
}code
关注个人公众号第一时间阅读有趣的技术故事
扫码关注:
也能够在微信搜索公众号便可关注我:codexiulian
渴望与你一块儿成长进步!继承