public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io. Serializable
extends AbstractSequentialList<E>java
implementsnode
與ArrayList對比git
LinkedList並無實現RandomAccess,而實現RandomAccess代表其支持快速(一般是固定時間)隨機訪問。此接口的主要目的是容許通常的算法更改其行爲,從而在將其應用到隨機或連續訪問列表時能提供良好的性能。這是LinkedList隨機訪問效率低的緣由之一。github
LinkedList不是 線程安全的,若是想使LinkedList變成線程安全的,能夠調用靜態類 Collections類中的synchronizedList方法:
List list=Collections.synchronizedList(new LinkedList(...));
LinkedList底層是雙向鏈表算法
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; } }
/** * LinkedList節點個數 */ transient int size = 0; /** * 指向頭節點的指針 */ transient Node<E> first; /** * 指向尾節點的指針 */ transient Node<E> last;
LinkedList()segmentfault
/** * 構造一個空鏈表. */ public LinkedList() { } /** * 根據指定集合c構造linkedList。先構造一個空linkedlist,在把指定集合c中的全部元素都添加到linkedList中。 */ public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
/** * 在表頭添加指定元素e */ private void linkFirst(E e) { final Node<E> f = first; //新建節點,節點的前指針指向null,後指針原來的頭節點 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若是原來的頭結點爲null,更新尾指針,不然使原來的頭結點f的前置指針指向新的頭結點newNode if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
/** * 在表尾插入指定元素e */ void linkLast(E e) { final Node<E> l = last; //新建節點newNode,節點的前指針指向l,後指針爲null final Node<E> newNode = new Node<>(l, e, null); last = newNode; //若是原來的尾結點爲null,更新頭指針,不然使原來的尾結點l的後置指針指向新的頭結點newNode if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
/** * 在指定節點succ以前插入指定元素e。指定節點succ不能爲null。 */ void linkBefore(E e, Node<E> succ) { //得到指定節點的前驅 final Node<E> pred = succ.prev; //新建節點newNode,前置指針指向pred,後置指針指向succ final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; //若是指定節點的前驅爲null,將newTouch設爲頭節點。不然更新pred的後置節點 if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
/** * 刪除指定節點,返回指定元素的值 */ E unlink(Node<E> x) { // assert x != null; // 保存指定節點的值 final E element = x.item; //獲得後繼節點 final Node<E> next = x.next; //獲得前驅節點 final Node<E> prev = x.prev; if (prev == null) { //若是刪除的節點是頭節點,令頭節點指向該節點的後繼節點 first = next; } else { //將前驅節點的後繼節點指向後繼節點 prev.next = next; x.prev = null; } if (next == null) { //若是刪除的節點是尾節點,令尾節點指向該節點的前驅節點 last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
/** * 刪除頭結點f,並返回頭結點的值. */ private E unlinkFirst(Node<E> f) { //保存頭結點的值 final E element = f.item; // 保存頭結點指向的下個節點 final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; //若是next爲null,將尾節點置爲null,不然將next的後置指針指向null if (next == null) last = null; else next.prev = null; size--; modCount++; //返回被刪除的頭結點的值 return element; }
/** * 刪除尾節點並返回尾節點的值 */ private E unlinkLast(Node<E> l) { // 保存尾節點的值 final E element = l.item; final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; //若是新的尾節點爲null,頭結點置爲null,不然將新的尾節點的後置指針指向null if (prev == null) first = null; else prev.next = null; size--; modCount++; //返回被刪除的尾節點的值 return element; }
步驟:數組
/** * 將元素添加到鏈表尾部 */ public boolean add(E e) { linkLast(e); return true; } /** * 在表尾插入指定元素e */ void linkLast(E e) { final Node<E> l = last; //新建節點newNode,節點的前指針指向l,後指針爲null final Node<E> newNode = new Node<>(l, e, null); last = newNode; //若是原來的尾結點爲null,更新頭指針,不然使原來的尾結點l的後置指針指向新的頭結點newNode if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
/** * 在指定位置添加元素 */ public void add(int index, E element) { //檢查索引是否處於[0-size]之間 checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
步驟:安全
/** * 插入指定集合到鏈尾 */ public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } /** * 插入指定集合到鏈尾的指定位置 */ public boolean addAll(int index, Collection<? extends E> c) { //1:檢查index範圍是否在size以內 checkPositionIndex(index); //2:toArray()方法把集合的數據存到對象數組中 Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; //3:獲得插入位置的前驅節點和後繼節點 Node<E> pred, succ; //若是插入位置爲尾部,前驅節點爲last,後繼節點爲null if (index == size) { succ = null; pred = last; } else { //不然,調用node()方法獲得後繼節點,再獲得前驅節點 succ = node(index); pred = succ.prev; } // 4:遍歷數據將數據插入 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; } //若是插入位置在尾部,重置last節點 if (succ == null) { last = pred; }//不然,將插入的鏈表與先前鏈表鏈接起來 else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; }
/** * 在表頭插入指定元素. */ public void addFirst(E e) { linkFirst(e); } /** * 在表頭添加指定元素e */ private void linkFirst(E e) { final Node<E> f = first; //新建節點,節點的前指針指向null,後指針原來的頭節點 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若是原來的頭結點爲null,更新尾指針,不然使原來的頭結點f的前置指針指向新的頭結點newNode if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
/** * 返回指定索引處的元素 */ public E get(int index) { //檢查index範圍是否在size以內 checkElementIndex(index); //調用node(index)去找到index對應的node而後返回它的值 return node(index).item; } /** * 返回在指定索引處的非空元素 */ Node<E> node(int 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; } }
/** * 返回鏈表中的頭結點的值. */ public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } /** * 獲取表頭節點的值,頭節點爲空拋出異常 */ public E element() { return getFirst(); } /** * 返回頭節點的元素,若是鏈表爲空則返回null */ public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } /** * 返回隊列的頭元素,若是頭節點爲空則返回空 */ public E peekFirst() { final Node<E> f = first; return (f == null) ? null : f.item; }
區別: getFirst(),element(),peek(),peekFirst() 這四個獲取頭結點方法的區別在於對鏈表爲空時的處理,是拋出異常仍是返回null。
getFirst() 和element() 方法將會在鏈表爲空時,拋出異常
element()方法的內部就是使用getFirst()實現的。它們會在鏈表爲空時,拋出NoSuchElementExceptiondom
/** * 返回鏈表中的尾結點的值. */ public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } /** * 返回隊列的尾元素,若是尾節點爲空則返回空 */ public E peekLast() { final Node<E> l = last; return (l == null) ? null : l.item; }
區別: getLast() 方法在鏈表爲空時,會拋出NoSuchElementException,而peekLast() 則不會,只是會返回 null。ide
/** * 正向遍歷鏈表,返回指定元素第一次出現時的索引。若是元素沒有出現,返回-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--; if (x.item == null) return index; } } else { //從尾遍歷 for (Node<E> x = last; x != null; x = x.prev) { index--; if (o.equals(x.item)) return index; } } return -1; }
/** * 刪除並返回棧頭元素 */ public E pop() { return removeFirst(); } /** * 刪除並返回頭節點,若是鏈表爲空,拋出異常 */ public E remove() { return removeFirst(); } /** * 刪除並返回表頭元素. */ 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); } /** * 刪除並返回隊列的最後個元素,若是尾節點爲空,則返回null. */ public E pollLast() { final Node<E> l = last; return (l == null) ? null : unlinkLast(l); }
區別: removeLast()在鏈表爲空時將拋出NoSuchElementException,而pollLast()方法返回null。
/** * 正向遍歷鏈表,刪除出現的第一個值爲指定對象的節點 */ public boolean remove(Object o) { //LinkedList容許存放Null //若是刪除對象爲null 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) { // assert x != null; // 保存指定節點的值 final E element = x.item; //獲得後繼節點 final Node<E> next = x.next; //獲得前驅節點 final Node<E> prev = x.prev; if (prev == null) { //若是刪除的節點是頭節點,令頭節點指向該節點的後繼節點 first = next; } else { //將前驅節點的後繼節點指向後繼節點 prev.next = next; x.prev = null; } if (next == null) { //若是刪除的節點是尾節點,令尾節點指向該節點的前驅節點 last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
/** * 判斷鏈表是否包含指定對象o */ public boolean contains(Object o) { return indexOf(o) != -1; }
/** * 替換指定索引處的元素爲指定元素element */ public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
參考資料:
https://segmentfault.com/a/11...
https://blog.csdn.net/panweiw...
https://github.com/Snailclimb...