LinkedList 繼承於AbstractSequentialList的雙向鏈表。它也能夠被看成堆棧、隊列或雙端隊列進行操做。
LinkedList 實現 List 接口,能對它進行隊列操做。
LinkedList 實現 Deque 接口,即能將LinkedList看成雙端隊列使用。
LinkedList 實現了Cloneable接口,即覆蓋了函數clone(),能克隆。
LinkedList 實現java.io.Serializable接口,這意味着LinkedList支持序列化,能經過序列化去傳輸。
LinkedList 是非同步的。html
java.lang.Object ↳ java.util.AbstractCollection<E> ↳ java.util.AbstractList<E> ↳ java.util.AbstractSequentialList<E> ↳ java.util.LinkedList<E> public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList apijava
// 實際元素個數 transient int size = 0; // 頭節點 transient Node<E> first; // 尾節點 transient Node<E> last; //注意,頭節點、尾節點都有transient關鍵字修飾,這也意味着在序列化時該域是不會序列化的。
內部類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 boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { //鏈表尾節點 final Node<E> l = last; //以尾節點爲前驅節點建立一個新節點 final Node<E> newNode = new Node<>(l, e, null); //將鏈表尾節點指向新節點 last = newNode; if (l == null)//若是鏈表爲空,那麼該節點既是頭節點也是尾節點 first = newNode; else//鏈表不爲空,那麼將該結點做爲原鏈表尾部的後繼節點 l.next = newNode; size++;//增長尺寸 modCount++; }
public void add(int index, E element) { checkPositionIndex(index); //檢查索引是否處於[0-size]之間 if (index == size)//添加在鏈表尾部 linkLast(element); else//添加在鏈表中間 linkBefore(element, node(index)); } void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
刪除和添加相反不作多餘解釋了。api
一、LinkedList 其實是經過雙向鏈表去實現的,增刪效率高,索引效率低。它包含一個很是重要的內部類:Node。Node是雙向鏈表節點所對應的數據結構,它包括的屬性有:當前節點所包含的值,上一個節點,下一個節點。
二、從LinkedList的實現方式中能夠發現,它不存在LinkedList容量不足的問題。
三、LinkedList實現java.io.Serializable。當寫入到輸出流時,先寫入「容量」,再依次寫入「每個節點保護的值」;當讀出輸入流時,先讀取「容量」,再依次讀取「每個元素」。
四、因爲LinkedList實現了Deque,而Deque接口定義了在雙端隊列兩端訪問元素的方法。提供插入、移除和檢查元素的方法。每種方法都存在兩種形式:一種形式在操做失敗時拋出異常,另外一種形式返回一個特殊值(null 或 false,具體取決於操做)。數據結構
import java.util.List; import java.util.Iterator; import java.util.LinkedList; import java.util.NoSuchElementException; /* * @desc 測試LinkedList的幾種遍歷方式和效率 */ public class LinkedListThruTest { public static void main(String[] args) { // 經過Iterator遍歷LinkedList iteratorLinkedListThruIterator(getLinkedList()) ; // 經過快速隨機訪問遍歷LinkedList iteratorLinkedListThruForeach(getLinkedList()) ; // 經過for循環的變種來訪問遍歷LinkedList iteratorThroughFor2(getLinkedList()) ; // 經過PollFirst()遍歷LinkedList iteratorThroughPollFirst(getLinkedList()) ; // 經過PollLast()遍歷LinkedList iteratorThroughPollLast(getLinkedList()) ; // 經過removeFirst()遍歷LinkedList iteratorThroughRemoveFirst(getLinkedList()) ; // 經過removeLast()遍歷LinkedList iteratorThroughRemoveLast(getLinkedList()) ; } private static LinkedList getLinkedList() { LinkedList llist = new LinkedList(); for (int i=0; i<100000; i++) llist.addLast(i); return llist; } /** * 經過快迭代器遍歷LinkedList */ private static void iteratorLinkedListThruIterator(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); for(Iterator iter = list.iterator(); iter.hasNext();) iter.next(); // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorLinkedListThruIterator:" + interval+" ms"); } /** * 經過快速隨機訪問遍歷LinkedList */ private static void iteratorLinkedListThruForeach(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); int size = list.size(); for (int i=0; i<size; i++) { list.get(i); } // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorLinkedListThruForeach:" + interval+" ms"); } /** * 經過另一種for循環來遍歷LinkedList */ private static void iteratorThroughFor2(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); for (Integer integ:list) ; // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughFor2:" + interval+" ms"); } /** * 經過pollFirst()來遍歷LinkedList */ private static void iteratorThroughPollFirst(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); while(list.pollFirst() != null) ; // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughPollFirst:" + interval+" ms"); } /** * 經過pollLast()來遍歷LinkedList */ private static void iteratorThroughPollLast(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); while(list.pollLast() != null) ; // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughPollLast:" + interval+" ms"); } /** * 經過removeFirst()來遍歷LinkedList */ private static void iteratorThroughRemoveFirst(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); try { while(list.removeFirst() != null) ; } catch (NoSuchElementException e) { } // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughRemoveFirst:" + interval+" ms"); } /** * 經過removeLast()來遍歷LinkedList */ private static void iteratorThroughRemoveLast(LinkedList<Integer> list) { if (list == null) return ; // 記錄開始時間 long start = System.currentTimeMillis(); try { while(list.removeLast() != null) ; } catch (NoSuchElementException e) { } // 記錄結束時間 long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughRemoveLast:" + interval+" ms"); } }
輸出結果函數
iteratorLinkedListThruIterator:8 ms iteratorLinkedListThruForeach:3724 ms iteratorThroughFor2:5 ms iteratorThroughPollFirst:8 ms iteratorThroughPollLast:6 ms iteratorThroughRemoveFirst:2 ms iteratorThroughRemoveLast:2 ms
因而可知,遍歷LinkedList時,使用removeFist()或removeLast()效率最高。但用它們遍歷時,會刪除原始數據;若單純只讀取,而不刪除,應該使用第3種遍歷方式。
不管如何,千萬不要經過隨機訪問去遍歷LinkedList!測試