Java Review - LinkedList源码解读
文章目錄
- Pre
- 概述
- 底層數據結構-雙向鏈表
- 源碼解析
- 構造函數
- 方法源碼分析
- getFirst()
- getLast()
- remove相關方法
- remove(e)
- remove(index)
- removeFirst()
- removeLast()
- add()
- addAll()
- clear()
- get相關的方法
- set()
- isElementIndex()
- isPositionIndex()
- 查找操作
- indexOf
- lastIndexOf
- Queue 方法
- Deque 方法
Pre
Java Review - ArrayList 源碼解讀
概述
從上圖可知: LinkedList同時實現了List接口和Deque接口,既可以看作一個順序容器,又可以看作一個隊列(Queue),同時又可以看作一個棧(Stack) 。
當需要使用棧或者隊列時,可以考慮使用LinkedList,一方面是因為Java官方已經聲明不建議使用Stack類,更遺憾的是,Java里根本沒有一個叫做Queue的類(它是個接口名字)。
關于棧或隊列,現在的首選是ArrayDeque,它有著比LinkedList(當作棧或隊列使用時)有著更好的性能。
ArrayDeque 移步 https://www.nhooo.com/java/java-arraydeque.html
LinkedList的實現方式決定了所有跟下標相關的操作都是線性時間,而在首段或者末尾刪除元素只需要常數時間。
為追求效率LinkedList沒有實現同步(synchronized),如果需要多個線程并發訪問,可以先采用Collections.synchronizedList()方法對其進行包裝。
底層數據結構-雙向鏈表
-
LinkedList底層通過雙向鏈表實現 。
-
雙向鏈表的每個節點用內部類Node表示。LinkedList通過first和last引用分別指向鏈表的第一個和最后一個元素。
-
沒有所謂的啞元,當鏈表為空的時候first和last都指向null。
其中Node是私有的內部類:
源碼解析
構造函數
/*** Constructs an empty list.*/public LinkedList() {}/*** Constructs a list containing the elements of the specified* collection, in the order they are returned by the collection's* iterator.** @param c the collection whose elements are to be placed into this list* @throws NullPointerException if the specified collection is null*/public LinkedList(Collection<? extends E> c) {this();addAll(c);}方法源碼分析
getFirst()
獲取第一個元素
/*** Returns the first element in this list.** @return the first element in this list* @throws NoSuchElementException if this list is empty*/public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;}getLast()
獲取最后一個元素
/*** Returns the last element in this list.** @return the last element in this list* @throws NoSuchElementException if this list is empty*/public E getLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return l.item;}remove相關方法
有兩個版本,
- 一個是刪除跟指定元素相等的第一個元素remove(Object o),
- 一個是刪除指定下標處的元素remove(int index)
remove(e)
【boolean remove(Object o) 】
/*** Removes the first occurrence of the specified element from this list,* if it is present. If this list does not contain the element, it is* unchanged. More formally, removes the element with the lowest index* {@code i} such that* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>* (if such an element exists). Returns {@code true} if this list* contained the specified element (or equivalently, if this list* changed as a result of the call).** @param o element to be removed from this list, if present* @return {@code true} if this list contained the specified element*/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;} /*** Unlinks non-null node x.*/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;}指的是刪除第一次出現的這個元素, 如果沒有這個元素,則返回false;判讀的依據是equals方法, 如果equals,則直接unlink這個node;由于LinkedList可存放null元素,故也可以刪除第一次出現null的元素;
remove(index)
【remove(int index)】
remove(int index)使用的是下標計數, 只需要判斷該index是否有元素即可,如果有則直接unlink這個node。
/*** Removes the element at the specified position in this list. Shifts any* subsequent elements to the left (subtracts one from their indices).* Returns the element that was removed from the list.** @param index the index of the element to be removed* @return the element previously at the specified position* @throws IndexOutOfBoundsException {@inheritDoc}*/public E remove(int index) {checkElementIndex(index);return unlink(node(index));}removeFirst()
【刪除 頭部元素】
/*** Removes and returns the first element from this list.** @return the first element from this list* @throws NoSuchElementException if this list is empty*/public E removeFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return unlinkFirst(f);}/*** Unlinks non-null first node f.*/private E unlinkFirst(Node<E> f) {// assert f == first && f != null;final E element = f.item;final Node<E> next = f.next;f.item = null;f.next = null; // help GCfirst = next;if (next == null)last = null;elsenext.prev = null;size--;modCount++;return element;}removeLast()
/*** Removes and returns the last element from this list.** @return the last element from this list* @throws NoSuchElementException if this list is empty*/public E removeLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return unlinkLast(l);}/*** Unlinks non-null last node l.*/private E unlinkLast(Node<E> l) {// assert l == last && l != null;final E element = l.item;final Node<E> prev = l.prev;l.item = null;l.prev = null; // help GClast = prev;if (prev == null)first = null;elseprev.next = null;size--;modCount++;return element;}add()
add()方法有兩個版本:
- 一個是add(E e),該方法在LinkedList的末尾插入元素,因為有last指向鏈表末尾,在末尾插入元素的花費是常數時間。只需要簡單修改幾個相關引用即可
- 另一個是add(int index, E element),該方法是在指定下表處插入元素,需要先通過線性查找找到具體位置,然后修改相關引用完成插入操作。
add(int index, E element),
- 當index==size時,等同于add(E e);
- 如果不是,則分兩步: 1.先根據index找到要插入的位置,即node(index)方法;2.修改引用,完成插入操作。
上面代碼中的node(int index)函數有一點小小的技巧,因為鏈表雙向的,可以從開始往后找,也可以從結尾往前找,具體朝那個方向找取決于條件index < (size >> 1),也即是index是靠近前端還是后端。
/*** Returns the (non-null) Node at the specified element 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;}}從這里也可以看出,linkedList通過index檢索元素的效率沒有arrayList高
addAll()
addAll(index, c) 實現方式并不是直接調用add(index,e)來實現,主要是因為效率的問題,另一個是fail-fast中modCount只會增加1次;
/*** Appends all of the elements in the specified collection to the end of* this list, in the order that they are returned by the specified* collection's iterator. The behavior of this operation is undefined if* the specified collection is modified while the operation is in* progress. (Note that this will occur if the specified collection is* this list, and it's nonempty.)** @param c collection containing elements to be added to this list* @return {@code true} if this list changed as a result of the call* @throws NullPointerException if the specified collection is null*/public boolean addAll(Collection<? extends E> c) {return addAll(size, c);}/*** Inserts all of the elements in the specified collection into this* list, starting at the specified position. Shifts the element* currently at that position (if any) and any subsequent elements to* the right (increases their indices). The new elements will appear* in the list in the order that they are returned by the* specified collection's iterator.** @param index index at which to insert the first element* from the specified collection* @param c collection containing elements to be added to this list* @return {@code true} if this list changed as a result of the call* @throws IndexOutOfBoundsException {@inheritDoc}* @throws NullPointerException if the specified collection is null*/public boolean addAll(int index, Collection<? extends E> c) {checkPositionIndex(index);Object[] a = c.toArray();int numNew = a.length;if (numNew == 0)return false;Node<E> pred, succ;if (index == size) {succ = null;pred = last;} else {succ = node(index);pred = succ.prev;}for (Object o : a) {@SuppressWarnings("unchecked") E e = (E) o;Node<E> newNode = new Node<>(pred, e, null);if (pred == null)first = newNode;elsepred.next = newNode;pred = newNode;}if (succ == null) {last = pred;} else {pred.next = succ;succ.prev = pred;}size += numNew;modCount++;return true;}clear()
為了讓GC更快可以回收放置的元素,需要將node之間的引用關系賦空。
/*** Removes all of the elements from this list.* The list will be empty after this call returns.*/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 Iteratorfor (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++;}get相關的方法
【通過index獲取元素】
// Positional Access Operations/*** Returns the element at the specified position in this list.** @param index index of the element to return* @return the element at the specified position in this list* @throws IndexOutOfBoundsException {@inheritDoc}*/public E get(int index) {checkElementIndex(index);return node(index).item;} /*** Returns the first element in this list.** @return the first element in this list* @throws NoSuchElementException if this list is empty*/public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;}/*** Returns the last element in this list.** @return the last element in this list* @throws NoSuchElementException if this list is empty*/public E getLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return l.item;}get(int index)得到指定下標處元素的引用,通過調用node(int index)方法實現
set()
將某個位置的元素重新賦值。
set(int index, E element)方法將指定下標處的元素修改成指定值,也是先通過node(int index)找到對應下表元素的引用,然后修改Node中item的值
/*** Replaces the element at the specified position in this list with the* specified element.** @param index index of the element to replace* @param element element to be stored at the specified position* @return the element previously at the specified position* @throws IndexOutOfBoundsException {@inheritDoc}*/public E set(int index, E element) {checkElementIndex(index);Node<E> x = node(index);E oldVal = x.item;x.item = element;return oldVal;}isElementIndex()
/*** Tells if the argument is the index of an existing element.*/private boolean isElementIndex(int index) {return index >= 0 && index < size;}isPositionIndex()
/*** Tells if the argument is the index of a valid position for an* iterator or an add operation.*/private boolean isPositionIndex(int index) {return index >= 0 && index <= size;}查找操作
查找操作的本質是查找元素的下標
indexOf
查找第一次出現的index, 如果找不到返回-1
/*** Returns the index of the first occurrence of the specified element* in this list, or -1 if this list does not contain the element.* More formally, returns the lowest index {@code i} such that* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,* or -1 if there is no such index.** @param o element to search for* @return the index of the first occurrence of the specified element in* this list, or -1 if this list does not contain the element*/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;}lastIndexOf
查找最后一次出現的index, 如果找不到返回-1
/*** Returns the index of the last occurrence of the specified element* in this list, or -1 if this list does not contain the element.* More formally, returns the highest index {@code i} such that* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,* or -1 if there is no such index.** @param o element to search for* @return the index of the last occurrence of the specified element in* this list, or -1 if this list does not contain the element*/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;}Queue 方法
/*** Retrieves, but does not remove, the head (first element) of this list.** @return the head of this list, or {@code null} if this list is empty* @since 1.5*/public E peek() {final Node<E> f = first;return (f == null) ? null : f.item;}/*** Retrieves, but does not remove, the head (first element) of this list.** @return the head of this list* @throws NoSuchElementException if this list is empty* @since 1.5*/public E element() {return getFirst();}/*** Retrieves and removes the head (first element) of this list.** @return the head of this list, or {@code null} if this list is empty* @since 1.5*/public E poll() {final Node<E> f = first;return (f == null) ? null : unlinkFirst(f);}/*** Retrieves and removes the head (first element) of this list.** @return the head of this list* @throws NoSuchElementException if this list is empty* @since 1.5*/public E remove() {return removeFirst();}/*** Adds the specified element as the tail (last element) of this list.** @param e the element to add* @return {@code true} (as specified by {@link Queue#offer})* @since 1.5*/public boolean offer(E e) {return add(e);}Deque 方法
/*** Inserts the specified element at the front of this list.** @param e the element to insert* @return {@code true} (as specified by {@link Deque#offerFirst})* @since 1.6*/public boolean offerFirst(E e) {addFirst(e);return true;}/*** Inserts the specified element at the end of this list.** @param e the element to insert* @return {@code true} (as specified by {@link Deque#offerLast})* @since 1.6*/public boolean offerLast(E e) {addLast(e);return true;}/*** Retrieves, but does not remove, the first element of this list,* or returns {@code null} if this list is empty.** @return the first element of this list, or {@code null}* if this list is empty* @since 1.6*/public E peekFirst() {final Node<E> f = first;return (f == null) ? null : f.item;}/*** Retrieves, but does not remove, the last element of this list,* or returns {@code null} if this list is empty.** @return the last element of this list, or {@code null}* if this list is empty* @since 1.6*/public E peekLast() {final Node<E> l = last;return (l == null) ? null : l.item;}/*** Retrieves and removes the first element of this list,* or returns {@code null} if this list is empty.** @return the first element of this list, or {@code null} if* this list is empty* @since 1.6*/public E pollFirst() {final Node<E> f = first;return (f == null) ? null : unlinkFirst(f);}/*** Retrieves and removes the last element of this list,* or returns {@code null} if this list is empty.** @return the last element of this list, or {@code null} if* this list is empty* @since 1.6*/public E pollLast() {final Node<E> l = last;return (l == null) ? null : unlinkLast(l);}/*** Pushes an element onto the stack represented by this list. In other* words, inserts the element at the front of this list.** <p>This method is equivalent to {@link #addFirst}.** @param e the element to push* @since 1.6*/public void push(E e) {addFirst(e);}/*** Pops an element from the stack represented by this list. In other* words, removes and returns the first element of this list.** <p>This method is equivalent to {@link #removeFirst()}.** @return the element at the front of this list (which is the top* of the stack represented by this list)* @throws NoSuchElementException if this list is empty* @since 1.6*/public E pop() {return removeFirst();}/*** Removes the first occurrence of the specified element in this* list (when traversing the list from head to tail). If the list* does not contain the element, it is unchanged.** @param o element to be removed from this list, if present* @return {@code true} if the list contained the specified element* @since 1.6*/public boolean removeFirstOccurrence(Object o) {return remove(o);}/*** Removes the last occurrence of the specified element in this* list (when traversing the list from head to tail). If the list* does not contain the element, it is unchanged.** @param o element to be removed from this list, if present* @return {@code true} if the list contained the specified element* @since 1.6*/public boolean removeLastOccurrence(Object o) {if (o == null) {for (Node<E> x = last; x != null; x = x.prev) {if (x.item == null) {unlink(x);return true;}}} else {for (Node<E> x = last; x != null; x = x.prev) {if (o.equals(x.item)) {unlink(x);return true;}}}return false;}總結
以上是生活随笔為你收集整理的Java Review - LinkedList源码解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Review - ArrayL
- 下一篇: Java Review - Queue和