LinkedList的原始碼分析(基於jdk1.8)
阿新 • • 發佈:2018-12-18
1.初始化
public LinkedList() { }
並未開闢任何類似於陣列一樣的儲存空間,那麼連結串列是如何儲存元素的呢?
2.Node型別
儲存到連結串列中的元素會被封裝為一個Node型別的結點。並且連結串列只需記錄第一個結點的位置和最後一個結點的位置。然後每一個結點,前後連線,就可以串起來變成一整個連結串列。
transient Node<E> first;//指向連結串列的第一個結點 transient Node<E> last;//指向連結串列的最後一個結點
//LinkedList中有一個內部類Node型別
privatestatic 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; } }
3.新增元素
public boolean add(E e) { //預設連結到連結串列末尾linkLast(e); return true; } void linkLast(E e) { //用l記錄當前連結串列的最後一個結點物件 final Node<E> l = last; //建立一個新結點物件,並且指定當前新結點的前一個結點為l final Node<E> newNode = new Node<>(l, e, null); //當前新結點就變成了連結串列的最後一個結點 last = newNode; if (l == null) //如果當前連結串列是空的,那麼新結點物件,同時也是連結串列的第一個結點first = newNode; else //如果當前連結串列不是空的,那麼最後一個結點的next就指向當前新結點 l.next = newNode; //元素個數增加 size++; //修改次數增加 modCount++; }
4.刪除元素
public boolean remove(Object o) { //分o是否是null討論,從頭到尾找到要刪除的元素o對應的Node結點物件,然後刪除 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; }
E unlink(Node<E> x) { final E element = x.item; //用next記錄被刪除結點的後一個結點 final Node<E> next = x.next; //用prev記錄被刪除結點的前一個結點 final Node<E> prev = x.prev; if (prev == null) { //如果刪除的是第一個結點,那麼被刪除的結點的後一個結點將成為第一個結點 first = next; } else { //否則被刪除結點的前一個結點的next應該指向被刪除結點的後一個結點 prev.next = next; //斷開被刪除結點與前一個結點的關係 x.prev = null; } if (next == null) { //如果刪除的是最後一個結點,那麼被刪除結點的前一個結點將變成最後一個結點 last = prev; } else { //否則被刪除結點的後一個結點的prev應該指向被刪除結點的額前一個結點 next.prev = prev; //斷開被刪除結點與後一個結點的關係 x.next = null; } //徹底把被刪除結點變成垃圾物件 x.item = null; //元素個數減少 size--; //修改次數增加 modCount++; return element; }
5.指定位置插入元素
public void add(int index, E element) { //檢查索引位置的合理性 checkPositionIndex(index); if (index == size) //如果位置是在最後,那麼連結到連結串列的最後 linkLast(element); else //否則在連結串列中間插入 //node(index)表示找到index位置的Node物件 linkBefore(element, node(index)); }
void linkBefore(E e, Node<E> succ) { // pred記錄被插入位置的前一個結點 final Node<E> pred = succ.prev; //構建一個新結點 final Node<E> newNode = new Node<>(pred, e, succ); //把新結點插入到succ的前面 succ.prev = newNode; //如果被插入點是連結串列的開頭,那麼新結點變成了連結串列頭 if (pred == null) first = newNode; else //否則pred的next就變成了新結點 pred.next = newNode;
//元素個數增加 size++; //修改次數增加 modCount++; }
6.總結
對於頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高。因為不涉及到移動元素,只需要修改前後結點的關係。也不需要涉及到擴容
此類雖然提供按照索引查詢與操作的方法,但是效率不高,如果需要按索引操作,那麼建議使用動態陣列