LinkedList和ArrayList都實現了List接口。因此有List的特性,同時LinkedList也實現了Deque,因此它也具備雙端隊列和棧的特性。java
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
//實際元素個數 transient int size = 0; //頭結點 transient Node<E> first; //尾結點 transient Node<E> last;
transient表示該域不能被序列化。first,last初始值都是null.node
這裏有一個內部類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; } }
public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
LinkedList內部的數據結構是一個雙向鏈表,因此不會有ArrayList那樣的指定容量構造器。函數
public boolean add(E e) { linkLast(e); return true; }
void linkLast(E e) { //final類型的l節點保存尾結點last final Node<E> l = last; //建立一個新的節點newNode,其前驅爲l,後繼爲null final Node<E> newNode = new Node<>(l, e, null); //將尾結點賦值爲新建立的節點。 last = newNode; //尾結點爲空,第一次添加 if (l == null) //新建節點爲頭結點 first = newNode; else //不然之前的尾結點的後繼指向新節點 l.next = newNode; //集合大小加1 size++; //結構性變化加一,目的和ArrayList同樣,檢查迭代過程當中結構變化。 modCount++; }
add()方法會將新添加的元素添加到鏈表的尾端。性能
讓咱們經過debug看看LinkedList添加元素過程,其結構的變化。
測試代碼:測試
public static void main(String[] args) { LinkedList<Integer> linkedList = new LinkedList<>(); linkedList.add(1); linkedList.add(2); linkedList.add(3); }
第一次添加後結構爲:this
第二次添加後結構爲:debug
第三次添加後結構爲:code
public E remove(int index) { //檢查是否越界 checkElementIndex(index); return unlink(node(index)); }
先經過node方法獲取index處的節點:blog
/** * Returns the (non-null) Node at the specified element index. */ Node<E> node(int index) { // assert isElementIndex(index); //size >> 1 等於 size/2 if (index < (size >> 1)) { //index在前半部分,從頭開始找 Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { //index在後半部分,從尾開始找 Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
而後再經過E unlink(Node
/** * Unlinks non-null node x. */ E unlink(Node<E> x) { // assert x != null; //x節點的元素 final E element = x.item; //後繼 final Node<E> next = x.next; //前驅 final Node<E> prev = x.prev; //x前驅爲空,刪除的節點是頭節點 if (prev == null) { first = next; } else { //x前驅節點的後繼節點變爲x的後繼節點 prev.next = next; //切斷前驅鏈接 x.prev = null; } //x後繼爲空,刪除的節點爲尾結點 if (next == null) { last = prev; } else { //x後繼節點的前驅變爲x的前驅節點 next.prev = prev; //切斷後繼鏈接 x.next = null; } //刪除節點元素置空 x.item = null; size--; modCount++; return element; }
public E get(int index) { //檢查索引 checkElementIndex(index); return node(index).item; }
/** * Returns the (non-null) Node at the specified element 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(int index)查找index對應的節點,而後返回對應的數據item。其中size >> 1這個是指size右移一位即size/2 。
Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x;
Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x;
LinkedList 是不能隨機訪問的,按照索引訪問效率較低,時間複雜度爲複雜度爲 O(N/2) 所以,LinkedList 刪除一個節點的時間複雜度爲 O(N) ,效率很高。