更多資訊可參考我的個人部落格:賤賤的夢想
LinkedList簡介 LinkedList 是一個繼承於AbstractSequentialList的雙向鏈表。它也可以被當作堆棧、隊列或雙端隊列進行操作。 LinkedList 實現 List 介面,能進行隊列操作。 LinkedList 實現 Deque 介面,即能將LinkedList當作雙端隊列使用。 ArrayList底層是由數組支援,而LinkedList 是由雙向鏈表實現的,其中的每個對象包含資料的同時還包含指向鏈表中前一個與後一個元素的引用。 LinkedList遍曆方式
LinkedList有以下幾種遍曆方式: 迭代器遍曆
Iterator<Integer> iterator = linkedList.iterator();while(iterator.hasNext()){ iterator.next();}
for迴圈get()遍曆
for(int i = 0; i < linkedList.size(); i++){ linkedList.get(i);}
Foreach迴圈遍曆
for(Integer i : linkedList);
通過pollFirst()或pollLast()遍曆
while(linkedList.size() != 0){ linkedList.pollFirst();}
通過removeFirst()或removeLast()遍曆
while(linkedList.size() != 0){ linkedList.removeFirst();}
效率測試
測試以上幾種遍曆方式的效率,部分代碼如下:
/************************** 遍曆操作 ************************/System.out.println("-----------------------------------------");linkedList.clear();for(int i = 0; i < 100000; i++){ linkedList.add(i);}// 迭代器遍曆long start = System.currentTimeMillis();Iterator<Integer> iterator = linkedList.iterator();while(iterator.hasNext()){ iterator.next();}long end = System.currentTimeMillis();System.out.println("Iterator:" + (end - start) +" ms");// 順序遍曆(隨機遍曆)start = System.currentTimeMillis();for(int i = 0; i < linkedList.size(); i++){ linkedList.get(i);}end = System.currentTimeMillis();System.out.println("for:" + (end - start) +" ms");// 另一種for迴圈遍曆start = System.currentTimeMillis();for(Integer i : linkedList);end = System.currentTimeMillis();System.out.println("for2:" + (end - start) +" ms");// 通過pollFirst()或pollLast()來遍曆LinkedListLinkedList<Integer> temp1 = new LinkedList<>();temp1.addAll(linkedList);start = System.currentTimeMillis();while(temp1.size() != 0){ temp1.pollFirst();}end = System.currentTimeMillis();System.out.println("pollFirst()或pollLast():" + (end - start) +" ms");// 通過removeFirst()或removeLast()來遍曆LinkedListLinkedList<Integer> temp2 = new LinkedList<>();temp2.addAll(linkedList);start = System.currentTimeMillis();while(temp2.size() != 0){ temp2.removeFirst();}end = System.currentTimeMillis();System.out.println("removeFirst()或removeLast():" + (end - start) +" ms");
輸出:
-----------------------------------------Iterator:17 msfor:8419 msfor2:12 mspollFirst()或pollLast():12 msremoveFirst()或removeLast():10 ms
由測試結果可以看出,遍曆LinkedList時,使用removeFirst()或removeLast()效率最高,而for迴圈get()效率最低,應避免使用這種方式進行。應當注意的是,使用pollFirst()或pollLast()或removeFirst()或removeLast()遍曆時,會刪除未經處理資料,若只單純的讀取,應當選用第一種或第三種方式。 LinkedList樣本
/** * @author GongchuangSu * @since 2016.05.11 */import java.util.Iterator;import java.util.LinkedList;public class LinkedListDemo { public static void main(String[] srgs){ LinkedList<Integer> linkedList = new LinkedList<>(); /************************** 基本操作 ************************/ linkedList.addFirst(0); // 添加元素到列表開頭 linkedList.add(1); // 在列表結尾添加元素 linkedList.add(2,2); // 在指定位置添加元素 linkedList.addLast(3); // 添加元素到列表結尾 System.out.println("LinkedList: " + linkedList); System.out.println("getFirst(): " + linkedList.getFirst()); // 返回此列表的第一個元素 System.out.println("getLast(): " + linkedList.getLast()); // 返回此列表的最後一個元素 System.out.println("removeFirst(): " + linkedList.removeFirst()); // 移除並返回此列表的第一個元素 System.out.println("removeLast(): " + linkedList.removeLast()); // 移除並返回此列表的最後一個元素 System.out.println("After remove:" + linkedList); System.out.println("contains(1) is :" + linkedList.contains(1)); // 判斷此列表包含指定元素,如果是,則返回true System.out.println("size is : " + linkedList.size()); // 返回此列表的元素個數 /************************** 位置訪問操作 ************************/ System.out.println("-----------------------------------------"); linkedList.set(1, 3); // 將此列表中指定位置的元素替換為指定的元素 System.out.println("After set(1, 3):" + linkedList); System.out.println("get(1): " + linkedList.get(1)); // 返回此列表中指定位置處的元素 /************************** Search操作 ************************/ System.out.println("-----------------------------------------"); linkedList.add(3); System.out.println("indexOf(3): " + linkedList.indexOf(3)); // 返回此列表中首次出現的指定元素的索引 System.out.println("lastIndexOf(3): " + linkedList.lastIndexOf(3));// 返回此列表中最後出現的指定元素的索引 /************************** Queue操作 ************************/ System.out.println("-----------------------------------------"); System.out.println("peek(): " + linkedList.peek()); // 擷取但不移除此列表的頭 System.out.println("element(): " + linkedList.element()); // 擷取但不移除此列表的頭 linkedList.poll(); // 擷取並移除此列表的頭 System.out.println("After poll():" + linkedList); linkedList.remove(); System.out.println("After remove():" + linkedList); // 擷取並移除此列表的頭 linkedList.offer(4); System.out.println("After offer(4):" + linkedList); // 將指定元素添加到此列表的末尾 /************************** Deque操作 ************************/ System.out.println("-----------------------------------------"); linkedList.offerFirst(2); // 在此列表的開頭插入指定的元素 System.out.println("After offerFirst(2):" + linkedList); linkedList.offerLast(5); // 在此列表末尾插入指定的元素 System.out.println("After offerLast(5):" + linkedList); System.out.println("peekFirst(): " + linkedList.peekFirst()); // 擷取但不移除此列表的第一個元素 System.out.println("peekLast(): " + linkedList.peekLast()); // 擷取但不移除此列表的第一個元素 linkedList.pollFirst(); // 擷取並移除此列表的第一個元素 System.out.println("After pollFirst():" + linkedList); linkedList.pollLast(); // 擷取並移除此列表的最後一個元素 System.out.println("After pollLast():" + linkedList); linkedList.push(2); // 將元素推入此列表所表示的堆棧(插入到列表的頭) System.out.println("After push(2):" + linkedList); linkedList.pop(); // 從此列表所表示的堆棧處彈出一個元素(擷取並移除列表第一個元素) System.out.println("After pop():" + linkedList); linkedList.add(3); linkedList.removeFirstOccurrence(3); // 從此列表中移除第一次出現的指定元素(從頭部到尾部遍曆列表) System.out.println("After removeFirstOccurrence(3):" + linkedList); linkedList.removeLastOccurrence(3); // 從此列表中移除最後一次出現的指定元素(從頭部到尾部遍曆列表) System.out.println("After removeFirstOccurrence(3):" + linkedList); /************************** 遍曆操作 ************************/ System.out.println("-----------------------------------------"); linkedList.clear(); for(int i = 0; i < 100000; i++){ linkedList.add(i); } // 迭代器遍曆 long start = System.currentTimeMillis(); Iterator<Integer> iterator = linkedList.iterator(); while(iterator.hasNext()){ iterator.next(); } long end = System.currentTimeMillis(); System.out.println("Iterator:" + (end - start) +" ms"); // 順序遍曆(隨機遍曆) start = System.currentTimeMillis(); for(int i = 0; i < linkedList.size(); i++){ linkedList.get(i); } end = System.currentTimeMillis(); System.out.println("for:" + (end - start) +" ms"); // 另一種for迴圈遍曆 start = System.currentTimeMillis(); for(Integer i : linkedList); end = System.currentTimeMillis(); System.out.println("for2:" + (end - start) +" ms"); // 通過pollFirst()或pollLast()來遍曆LinkedList LinkedList<Integer> temp1 = new LinkedList<>(); temp1.addAll(linkedList); start = System.currentTimeMillis(); while(temp1.size() != 0){ temp1.pollFirst(); } end = System.currentTimeMillis(); System.out.println("pollFirst()或pollLast():" + (end - start) +" ms"); // 通過removeFirst()或removeLast()來遍曆LinkedList LinkedList<Integer> temp2 = new LinkedList<>(); temp2.addAll(linkedList); start = System.currentTimeMillis(); while(temp2.size() != 0){ temp2.removeFirst(); } end = System.currentTimeMillis(); System.out.println("removeFirst()或removeLast():" + (end - start) +" ms"); }}/**OutputLinkedList: [0, 1, 2, 3]getFirst(): 0getLast(): 3removeFirst(): 0removeLast(): 3After remove:[1, 2]contains(1) is :truesize is : 2-----------------------------------------After set(1, 3):[1, 3]get(1): 3-----------------------------------------indexOf(3): 1lastIndexOf(3): 2-----------------------------------------peek(): 1element(): 1After poll():[3, 3]After remove():[3]After offer(4):[3, 4]-----------------------------------------After offerFirst(2):[2, 3, 4]After offerLast(5):[2, 3, 4, 5]peekFirst(): 2peekLast(): 5After pollFirst():[3, 4, 5]After pollLast():[3, 4]After push(2):[2, 3, 4]After pop():[3, 4]After removeFirstOccurrence(3):[4, 3]After removeFirstOccurrence(3):[4]-----------------------------------------Iterator:17 msfor:8419 msfor2:12 mspollFirst()或pollLast():12 msremoveFirst()或removeLast():10 ms*/
LinkedList和ArrayList比較 LinkedList中插入元素很快,而ArrayList中插入元素很慢 LinkedList中隨機訪問很慢,而ArrayList中隨機訪問很快
LinkedList源碼解析
package java.util;public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{ transient int size = 0; // 第一個結點 transient Node<E> first; // 最後一個結點 transient Node<E> last; // 構造一個空列表 public LinkedList() { } // 構造一個包含指定 Collection 中的元素的列表, // 這些元素按其 Collection 的迭代器返回的順序排列 public LinkedList(Collection<? extends E> c) { this(); addAll(c); } // 返回此列表的第一個元素 public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } // 返回此列表的最後一個元素 public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } // 移除並返回此列表的第一個元素 public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } // 移除並返回此列表的最後一個元素 public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); } // 將指定元素插入此列表的開頭 public void addFirst(E e) { linkFirst(e); } // 將指定元素添加到此列表的結尾 public void addLast(E e) { linkLast(e); } // 判斷此列表包含指定元素,如果是,則返回true public boolean contains(Object o) { return indexOf(o) != -1; } // 返回此列表的元素個數 public int size() { return size; } // 將指定元素添加到此列表的結尾 public boolean add(E e) { linkLast(e); return true; } // 從此列表中移除首次出現的指定元素(如果存在返回true,否則返回false) public boolean remove(Object o) { 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; } // 添加指定 collection 中的所有元素到此列表的結尾, // 順序是指定 collection 的迭代器返回這些元素的順序 public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } // 將指定 collection 中的所有元素從指定位置開始插入此列表 public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index);// 檢查index的範圍 Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) // 如果c為空白,則返回false return false; Node<E> pred, succ; if (index == size) { // 插入位置為列表末尾 succ = null; pred = last; } else { succ = node(index); // 插入位置不是列表末尾 pred = succ.prev; } // 將元素添加到pred末尾 for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); if (pred == null) first = newNode; else pred.next = newNode; pred = newNode; } // 將剩餘元素整合一起 if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; } // 從此列表中移除所有元素 public void clear() { // Clearing all of the links between nodes is "unnecessary", but: // - helps a generational GC if the discarded nodes inhabit // more than one generation // - is sure to free memory even if there is a reachable Iterator for (Node<E> x = first; x != null; ) { Node<E> next = x.next; x.item = null; x.next = null; x.prev = null; x = next; } first = last = null; size = 0; modCount++; } /********************** 位置訪問操作 **************************/ // 返回此列表中指定位置處的元素 public E get(int index) { checkElementIndex(index); return node(index).item; } // 將此列表中指定位置的元素替換為指定的元素 public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; } // 在此列表中指定的位置插入指定的元素 public void add(int index, E element) { checkPositionIndex(index); if (index == size) // 插入到末尾 linkLast(element); else linkBefore(element, node(index)); } // 移除此列表中指定位置處的元素 public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } // (包存取權限)返回指定位置上的結點(非空) Node<E> node(int index) { // assert isElementIndex(index); // 根據指定位置是在左半邊還是在右半邊, // 來決定是用正向尋找還是反向尋找 if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } } /********************** Search操作 **************************/ // 返回此列表中首次出現的指定元素的索引, // 如果此列表中不包含該元素,則返回 -1 public int indexOf(Object o) { int index = 0; if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; } // 返回此列表中最後出現的指定元素的索引, // 如果此列表中不包含該元素,則返回 -1 public int lastIndexOf(Object o) { int index = size; if (o == null) { for (Node<E> x = last; x != null; x = x.prev) { index--;