心在山東身在吳,飄蓬江海漫嗟吁。
他時若遂凌雲志, 敢笑黃巢不丈夫。
——水滸傳
先上源代碼,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 }
Java鏈表中定義了一個內部類Node類,"node"是節點的意思.鏈表的基本元素是節點,(雙向鏈表)每個節點包含三個成員,分別是item:數據,next:指向鏈表下一個元素的指針,prev:指向上一個元素的指針
先看一下C中的鏈表:
頭指針變量保存了一個地址,它指向一個變量No.1,No.1中又保存了一個指針,它指向No.2,以此類推,直到No.X中保存的地址指向No.last,圖中最后一項為No.3,它指向NULL。
雙向鏈表每個元素中又加入了prev指針。
雙向鏈表圖:
但是java中沒有指向內存地址的指針,那么如何實現鏈表呢?
再看Java源代碼:

1 transient int size = 0; 2 3 /** 4 * Pointer to first node. 5 * Invariant: (first == null && last == null) || 6 * (first.prev == null && first.item != null) 7 */ 8 transient Node<E> first; 9 10 /** 11 * Pointer to last node. 12 * Invariant: (first == null && last == null) || 13 * (last.next == null && last.item != null) 14 */ 15 transient Node<E> last; 16 17 /** 18 * Constructs an empty list. 19 */ 20 public LinkedList() { 21 } 22 23 /** 24 * Constructs a list containing the elements of the specified 25 * collection, in the order they are returned by the collection's 26 * iterator. 27 * 28 * @param c the collection whose elements are to be placed into this list 29 * @throws NullPointerException if the specified collection is null 30 */ 31 public LinkedList(Collection<? extends E> c) { 32 this(); 33 addAll(c); 34 }
LinkedList類定義了兩個臨時節點first和last,兩個構造器.一個無參構造和一個帶參構造,無參構造創建鏈表實例,帶參構造可以把一個集合整體加入鏈表
下面看一下add()方法:
1 public boolean add(E e) { 2 linkLast(e); 3 return true; 4 }
1 void linkLast(E e) { 2 final Node<E> l = last; 3 final Node<E> newNode = new Node<>(l, e, null); 4 last = newNode; 5 if (l == null) 6 first = newNode; 7 else 8 l.next = newNode; 9 size++; 10 modCount++; 11 }
畫圖:
初始鏈表為空的情況:prev和next都是null,item是e,這里假設傳入的數據是No.1,No.2...;
此時再加入元素:
加入第三個元素:
加入第四個元素:
以此類推。。。
可見java中鏈表是用引用變量指向節點來代替C中的指針變量指向內存地址。
每次加入新的元素,只需要將原last元素的next指向新加入元素的實例,把新加入元素的prev指向原last元素的實例。
再看下add(int index, E element)方法:
1 public void add(int index, E element) { 2 checkPositionIndex(index); 3 4 if (index == size) 5 linkLast(element); 6 else 7 linkBefore(element, node(index)); 8 }
1 Node<E> node(int index) { 2 // assert isElementIndex(index); 3 4 if (index < (size >> 1)) { 5 Node<E> x = first; 6 for (int i = 0; i < index; i++) 7 x = x.next; 8 return x; 9 } else { 10 Node<E> x = last; 11 for (int i = size - 1; i > index; i--) 12 x = x.prev; 13 return x; 14 } 15 }
這里假定傳入的index比size小,
node(int index)用很簡單的方式返回了位置為index的Node實例,然后執行linkBefore(E e, Node<E> succ)方法
1 void linkBefore(E e, Node<E> succ) { 2 // assert succ != null; 3 final Node<E> pred = succ.prev; 4 final Node<E> newNode = new Node<>(pred, e, succ); 5 succ.prev = newNode; 6 if (pred == null) 7 first = newNode; 8 else 9 pred.next = newNode; 10 size++; 11 modCount++; 12 }
把newNode 的prev 指向原位置節點的prev節點,next 指向原位置節點;
把原位置節點的prev指向newNode;
最后把原位置節點的prev節點(如果有)的next指向newNode;如果沒有,則newNode為第一個節點,原位置節點變為第二個節點;
此處省略其他鏈表方法...原理是一樣的.