LinkedList詳解


一.關於 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     }
View Code

    描述:每一個節點中都包含了元素和前后節點的引用變量

三.一些重要的方法

  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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM