一.關於 LinkedList 常見內容
描述:實現 List<E> 接口;元素可排序,可重復,可為 null ,不是線程安全的.
繼承以及實現關系:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
描述: List<E> 接口定義了列表的方法和默認實現, AbstractSequentialList<E> 繼承自 AbstractList<E> ,在其基礎上又添加了迭代查詢的實現. Deque<E> 接口表示含有隊列、雙端隊列的API,是隊列的一種實現, Cloneable 接口表示可以克隆, Serializable 接口表示可以序列化,用於數據傳輸
二. LinkedList 的實現原理
LinkedList 是通過鏈表實現的,每一個元素都存放在一個鏈表的節點中,對列表的操作就是對鏈表的操作,由於不支持隨機訪問,所以 LinkedList 只能通過順序訪問(是鏈表結構導致的),但由於添加或者刪除元素時只是修改相關節點中對應的引用變量,所以單純的增刪操作比數組和 ArrayList 更快
三.定義的屬性和節點
屬性:
// 大小 transient int size = 0; // 頭結點 transient Node<E> first; // 尾節點 transient Node<E> last;
大小:表示列表當前存放的元素數量
頭結點:表示列表的第一個節點(引用)
尾節點:表示列表的最后一個節點(引用)
由節點的內容可以看出 LinkedList 維護的是一個雙向鏈表
節點:

1 private static class Node<E> { 2 E item; 3 Node<E> next; 4 Node<E> prev; 5 6 Node(Node<E> prev, E element, Node<E> next) { 7 this.item = element; 8 this.next = next; 9 this.prev = prev; 10 } 11 }
描述:每一個節點中都包含了元素和前后節點的引用變量
三.一些重要的方法
1.構造方法
1 public LinkedList() { 2 } 3 4 public LinkedList(Collection<? extends E> c) { 5 this(); 6 addAll(c); 7 }
描述: LinkedList 在創建是都是空的,沒有任何節點
2.node
1 // 查找指定位置的節點 2 Node<E> node(int index) { 3 // assert isElementIndex(index); 4 // index 近頭 5 if (index < (size >> 1)) { 6 Node<E> x = first; 7 for (int i = 0; i < index; i++) 8 x = x.next; 9 return x; 10 } 11 // index 近尾 12 else { 13 Node<E> x = last; 14 for (int i = size - 1; i > index; i--) 15 x = x.prev; 16 return x; 17 } 18 }
描述:為了提高效率,node方法在進行節點查找時,會先判斷index是近頭還是近尾,近頭就從頭結點開始查找,近尾就從尾節點開始查找;相似的,在進行元素查找時(即indexOf和lastIndexOf方法),也是使用的近頭和近尾再查找
3.linkFirst
1 // e 作為頭元素,頭插 2 private void linkFirst(E e) { 3 final Node<E> f = first; 4 // 新建一個節點,內容為 e 無前節點,后節點為原來的頭節點 5 final Node<E> newNode = new Node<>(null, e, f); 6 first = newNode; 7 if (f == null) 8 // 如果原頭節點不存在,即為空鏈表,則頭尾節點是同一個節點 9 last = newNode; 10 else 11 // 如果原頭節點存在,則將原頭節點的前一節點置為新建節點 12 f.prev = newNode; 13 size++; 14 modCount++; 15 }
描述:在列表頭添加一個新元素,新元素的節點作為列表的新的頭節點,應用有雙端隊列中頭部添加元素,壓棧操作
4.linkLast
1 // e 作為尾節點,尾插 2 void linkLast(E e) { 3 final Node<E> l = last; 4 // 新建一個節點,前一節點為原尾節點,無后一節點 5 final Node<E> newNode = new Node<>(l, e, null); 6 // 更新尾節點 7 last = newNode; 8 if (l == null) 9 // 若原尾節點為 null ,則為空鏈表,頭尾節點是同一節點 10 first = newNode; 11 else 12 // 否則原尾節點的下一個節點是新的尾節點 13 l.next = newNode; 14 size++; 15 modCount++; 16 }
描述:在列表尾部添加一個元素,應用有想隊列(單端)中添加元素
5.linkBefore
1 // e 元素插入某一元素之前,該元素不為 null 2 void linkBefore(E e, Node<E> succ) { 3 // assert succ != null; 4 // 定位目標節點的前一節點 5 final Node<E> pred = succ.prev; 6 // 新建節點的前一節點為目標節點的前一節點,后一節點為目標節點 7 final Node<E> newNode = new Node<>(pred, e, succ); 8 // 修改目標節點的前一節點為新節點 9 succ.prev = newNode; 10 if (pred == null) 11 // 如果目標節點的原前一節點為 null,則表示該節點為頭節點,需將新節點置為頭節點 12 first = newNode; 13 else 14 // 否則需將目標節點的原前一節點的下一節點置為新節點 15 pred.next = newNode; 16 size++; 17 modCount++; 18 }
6.unlink
1 // 刪除某一不為空的節點 2 E unlink(Node<E> x) { 3 // assert x != null; 4 // 取節點的內容和前后節點 5 final E element = x.item; 6 final Node<E> next = x.next; 7 final Node<E> prev = x.prev; 8 9 if (prev == null) { 10 // 前一節點為 null ,則該節點為頭節點,將頭節點置為其后一節點 11 first = next; 12 } else { 13 // 否則前一節點的后一節點置為該節點的后一節點,該節點的前一節點置為 null 14 prev.next = next; 15 x.prev = null; 16 } 17 18 if (next == null) { 19 // 如果該節點的后一節點為 null ,即該節點為尾節點,則將尾節點置為該節點的前一節點 20 last = prev; 21 } else { 22 // 否則該節點的后一節點的前一節點置為該節點的前一節點,該節點的后一節點置為 nulll 23 next.prev = prev; 24 x.next = null; 25 } 26 27 x.item = null; 28 size--; 29 modCount++; 30 return element; 31 }
7.unlinkFirst
1 // 頭刪 2 private E unlinkFirst(Node<E> f) { 3 // assert f == first && f != null; 4 // 取頭節點內容和后一節點 5 final E element = f.item; 6 final Node<E> next = f.next; 7 f.item = null; 8 f.next = null; // help GC 9 // 將頭節點置為原頭節點的后一節點 10 first = next; 11 if (next == null) 12 // 如果沒有后一個節點,即只有一個節點,則尾節點也置為 null 13 last = null; 14 else 15 // 否則后一個節點的前一節點置為 null 16 next.prev = null; 17 size--; 18 modCount++; 19 return element; 20 }
描述:從列表頭部刪除一個元素,應用有從隊列中取元素,應用有出棧
8.unlinkLast
1 // 尾刪 2 private E unlinkLast(Node<E> l) { 3 // assert l == last && l != null; 4 // 取尾節點的內容和其前一節點 5 final E element = l.item; 6 final Node<E> prev = l.prev; 7 l.item = null; 8 l.prev = null; // help GC 9 // 新的尾節點是原尾節點的前一節點 10 last = prev; 11 if (prev == null) 12 // 如果原尾節點沒有前一節點,即只有一個節點,則頭節點置為 null 13 first = null; 14 else 15 // 否則原尾結點的前一節點的下一節點置為 null 16 prev.next = null; 17 size--; 18 modCount++; 19 return element; 20 }
描述:從列表尾部刪除一個元素
9.定位方法
1 // 已存在的元素的 index 2 private boolean isElementIndex(int index) { 3 return index >= 0 && index < size; 4 } 5 6 // 迭代或者添加操作的有效位置的 index 7 private boolean isPositionIndex(int index) { 8 return index >= 0 && index <= size; 9 }
五.常用的API
1.get
1 public E get(int index) { 2 checkElementIndex(index); 3 // 查詢指定位置的節點 4 return node(index).item; 5 }
2.set
1 public E set(int index, E element) { 2 checkElementIndex(index); 3 Node<E> x = node(index); 4 E oldVal = x.item; 5 x.item = element; 6 return oldVal; 7 }
3.indexOf
1 public int indexOf(Object o) { 2 int index = 0; 3 // null 和非 null 的判斷方式不一樣 4 if (o == null) { 5 for (Node<E> x = first; x != null; x = x.next) { 6 if (x.item == null) 7 return index; 8 index++; 9 } 10 } else { 11 for (Node<E> x = first; x != null; x = x.next) { 12 if (o.equals(x.item)) 13 return index; 14 index++; 15 } 16 } 17 return -1; 18 }
描述:lastIndexOf也相似,只是開始的位置的尾節點,一次向前查找
4.add
1 public boolean add(E e) { 2 linkLast(e); 3 return true; 4 }
描述:add方法是直接調用尾插方法,強制返回true
5.remove
1 public E remove(int index) { 2 checkElementIndex(index); 3 return unlink(node(index)); 4 }
6.toArray
1 public Object[] toArray() { 2 Object[] result = new Object[size]; 3 int i = 0; 4 for (Node<E> x = first; x != null; x = x.next) 5 result[i++] = x.item; 6 return result; 7 }
描述:新建一個等長數組,遍歷集合挨個放入
6.隊列中定義的方法如:peek,poll,offer;以及棧定義的方法:push,pop
受限於個人水平,如有錯誤或者補充望請告知(博客園:xiao_lin_unit)