LinkedList 學習筆記

按照學習計劃,學習理解了LinkedList的源碼,同時在方法中寫了詳細註釋(在下方)

總結

LinkedList 是一個繼承自AbstractSequentialList 的 雙向鏈表,需要實現一個抽象方法,返回一個不可變的迭代器

    public abstract ListIterator<E> listIterator(int index);

線程不安全
不支持隨機訪問
LinkedList 實現了Deque 可以當做雙端隊列使用
LinkedList 沒有實現RandomAccess 它的循環效率要小於迭代器

知識點

快速失敗( fail-fast)

快速失敗是多線程情況下,對於數據不一致的處理方式
如下所示,判斷兩個字段

		private int expectedModCount = modCount;//fail-fast  快速失敗
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
  • modCount 記錄LinkedList 本身的操作
  • expectedModCount 記錄迭代器操作,他的初始值爲modCount

當迭代器內部發生了add和remove操作都會導致expectedModCount++
迭代器每次迭代,都會訪問checkForComodification()方法
發現數據不一致時,立即失敗,拋出ConcurrentModificationException 異常

雙端隊列 Deque

參考摘錄自 :雙端隊列

  • Deque 是 Double ended queue (雙端隊列) 的縮寫,讀音和 deck 一樣,蛋殼。
  • Deque 繼承自 Queue,直接實現了它的有 LinkedList, ArayDeque, ConcurrentLinkedDeque 等。
  • Deque 支持容量受限的雙端隊列,也支持大小不固定的。一般雙端隊列大小不確定。
  • Deque 接口定義了一些從頭部和尾部訪問元素的方法。比如分別在頭部、尾部進行插入、刪除、獲取元素。和 Queue

雙端隊列只允許在開始和結尾處進行操作,操作方式有:

insert 操作實例

請觀察添加順序和打印結果的不同之處:

    public static void main(String[] args) {
        LinkedList<String> var = new LinkedList<>();
        //insert
        var.offerLast("d");// 在尾結點的前面插入
        var.offerFirst("b");// 在開始位置 後面插入
        var.addFirst("a");//在開始位置添加
        var.addLast("c"); // 添加到尾結點
        var.listIterator().forEachRemaining(System.out::println);
    }

打印結果:
在這裏插入圖片描述

remove 操作實例

刪除指定位置:

    public static void main(String[] args) {
        LinkedList<String> var = new LinkedList<>();
        //insert
        var.offerLast("d");// 在尾結點的前面插入
        var.offerFirst("b");// 在開始位置 後面插入
        var.addFirst("a");//在開始位置添加
        var.addLast("c"); // 添加到尾結點
        var.removeFirst();
        var.listIterator().forEachRemaining(System.out::println);
    }

打印結果:
在這裏插入圖片描述

詳細註釋

import java.util.*;
import java.util.function.Consumer;

/**
 * AbstractSequentialList     -----------START
 * This class provides a skeletal implementation of the <tt>List</tt>
 * interface to minimize the effort required to implement this interface
 * backed by a "sequential access" data store (such as a linked list).  For
 * random access data (such as an array), <tt>AbstractList</tt> should be used
 * in preference to this class.<p>
 * List 接口的實現, 爲實現序列訪問的數據結構提供了最小化的接口實現,對於支持隨機訪問的List,應該優先採用 AbstractList
 * 最小化 = 只支持按照順序訪問 ,AbstractList 支持隨機訪問
 * 通俗點說 LinkedList 實現 AbstractSequentialList   ArrayList 實現 AbstractList
 * ArrayList 實現了RandomAccess接口(這個接口只是標記支持隨機訪問) LinkedList沒有
 * 支持 RandomAccess 的對象,遍歷時使用 get 比 迭代器更快
 * LinkedList 沒有實現RandomAccess 那麼他的get效率要小於迭代器
 * <p>
 * This class is the opposite of the <tt>AbstractList</tt> class in the sense
 * that it implements the "random access" methods (<tt>get(int index)</tt>,
 * <tt>set(int index, E element)</tt>, <tt>add(int index, E element)</tt> and
 * <tt>remove(int index)</tt>) on top of the list's list iterator, instead of
 * the other way around.<p>
 * To implement a list the programmer needs only to extend this class and
 * provide implementations for the <tt>listIterator</tt> and <tt>size</tt>
 * methods.  For an unmodifiable list, the programmer need only implement the
 * list iterator's <tt>hasNext</tt>, <tt>next</tt>, <tt>hasPrevious</tt>,
 * <tt>previous</tt> and <tt>index</tt> methods.<p>
 * For a modifiable list the programmer should additionally implement the list
 * iterator's <tt>set</tt> method.  For a variable-size list the programmer
 * should additionally implement the list iterator's <tt>remove</tt> and
 * <tt>add</tt> methods.<p>
 * AbstractSequentialList是AbstractList 類中與隨機訪問類相對(相反) 的實現
 * 你需要實現一個 ListIterator, 實現它的 hasNext(), hasPrevious(), next(), previous()
 * 如果你想讓它可修改,還需要實現 add(), remove(), set() 方法
 * 然後就可以獲得一個 不可變的 ListIterator
 * AbstractSequentialList     -----------END
 * <p>
 * Deque     -----------START
 * A linear collection that supports element insertion and removal at
 * both ends.  The name <i>deque</i> is short for "double ended queue"
 * and is usually pronounced "deck".  Most {@code Deque}
 * implementations place no fixed limits on the number of elements
 * they may contain, but this interface supports capacity-restricted
 * deques as well as those with no fixed size limit.
 * 一個支持元素插入和刪除的-- 線性集合--
 * deque =  double ended queue
 * 發音爲 deck
 * deque 支持容量受限的雙端隊列 ,也支持大小不固定,一般雙端隊列大小不確定
 *
 * <p>This interface defines methods to access the elements at both
 * ends of the deque.  Methods are provided to insert, remove, and
 * examine the element.  Each of these methods exists in two forms:
 * one throws an exception if the operation fails, the other returns a
 * special value (either {@code null} or {@code false}, depending on
 * the operation).  The latter form of the insert operation is
 * designed specifically for use with capacity-restricted
 * {@code Deque} implementations; in most implementations, insert
 * operations cannot fail.
 * 接口定義了從頭部和尾部訪問元素的方法,插入、刪除、獲取元素
 * 每個操作都有兩種方法,第一種在異常情況下會直接拋出異常,第二種則不會返回異常  會返回{code}
 * 比如first 操作
 * 1. addFirst
 * 2. offerFirst
 * 它寫的插入操作不能失敗! 實際是大多數情況下不能失敗??
 * Deque     ----------END
 * <p>
 * <p>
 * <p>
 * LinedList 是一個繼承自AbstractSequentialList 的 雙向鏈表,線程不安全(非同步的) , 不支持隨機訪問
 * LinedList 實現了Deque 可以當做雙端隊列使用
 *
 * @author 李東
 * @version 1.0
 * @date 2020/1/10 21:55
 */
public class MyLinkedList<E> extends AbstractSequentialList<E>
        implements List<E>, Deque<E>, Cloneable, java.io.Serializable {


    /**
     * linkedList 擁有三個成員變量
     */
    transient int size = 0;// 容量
    transient Node<E> first;// 頭結點
    transient Node<E> last;// 尾節點


    /**
     * 鏈表節點的定義
     *
     * @param <E>
     */
    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;
        }
    }


    /**
     * AbstractSequentialList 類的實現
     *
     * @return 不可變的 ListIterator
     */
    @Override
    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }


    /**
     * An iterator for lists that allows the programmer
     * to traverse the list in either direction, modify
     * the list during iteration, and obtain the iterator's
     * current position in the list. A {@code ListIterator}
     * has no current element; its <I>cursor position</I> always
     * lies between the element that would be returned by a call
     * to {@code previous()} and the element that would be
     * returned by a call to {@code next()}.
     * An iterator for a list of length {@code n} has {@code n+1} possible
     * cursor positions, as illustrated by the carets ({@code ^}) below:
     * <p>
     * 運行的操作:
     * 1. 允許任意方向的遍歷  也就是說
     * ListIterator  可以前後迭代
     * Iterator  只能向前迭代
     * 2. 迭代運行期間支持修改
     * ListIterator  可以 set 和add
     * Iterator  只能刪除
     * 3. 列表當前位置 總是位於調用返回的之間
     * 這個位置稱之爲遊標
     * 他第一次存在於 0 這個下標之前
     * 他的總大小爲  n+1
     * <PRE>
     * Element(0)   Element(1)   Element(2)   ... Element(n-1)
     * cursor positions:  ^            ^            ^            ^                  ^
     * </PRE>
     */
    private class ListItr implements ListIterator<E> {

        /**
         * 四個成員變量
         */
        private Node<E> lastReturned;//上一次迭代的節點
        private Node<E> next; //下一個節點
        private int nextIndex;//記錄當前遊標的位置,沒有下標的概念
        private int expectedModCount = modCount;//fail-fast  快速失敗

        /**
         * 返回一個固定位置的迭代器
         */
        ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }

        /**
         * * Returns {@code true} if this list iterator has more elements when
         * * traversing the list in the forward direction. (In other words,
         * * returns {@code true} if {@link #next} would return an element rather
         * * than throwing an exception.)
         *
         * @return 下個節點是否存在
         */
        public boolean hasNext() {
            return nextIndex < size;
        }

        /**
         * Returns the next element in the list and advances the cursor position.
         * This method may be called repeatedly to iterate through the list,
         * or intermixed with calls to {@link #previous} to go back and forth.
         * (Note that alternating calls to {@code next} and {@code previous}
         * will return the same element repeatedly.)
         * <p>
         * 返回下個節點 並向前移動遊標
         * 這個方法可以用來遍歷列表
         * 也可以使用 {@link #previous}  方法
         *
         * @return
         */
        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();

            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }

        /**
         * Returns {@code true} if this list iterator has more elements when
         * traversing the list in the reverse direction.  (In other words,
         * returns {@code true} if {@link #previous} would return an element
         * rather than throwing an exception.)
         *
         * @return {@code true} if the list iterator has more elements when
         * traversing the list in the reverse direction
         * <p>
         * 判斷遊標前面是否有元素,循環就完事了
         */
        public boolean hasPrevious() {
            return nextIndex > 0;
        }

        /**
         * Returns the previous element in the list and moves the cursor
         * position backwards.  This method may be called repeatedly to
         * iterate through the list backwards, or intermixed with calls to
         * {@link #next} to go back and forth.  (Note that alternating calls
         * to {@code next} and {@code previous} will return the same
         * element repeatedly.)
         *
         * @return the previous element in the list
         * @throws NoSuchElementException if the iteration has no previous
         *                                element
         *                                <p>
         *                                <p>
         *                                返回遊標前面的元素,同時遊標前移一位
         *                                功能和next 相反
         */
        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }

        /**
         * Returns the index of the element that would be returned by a
         * subsequent call to {@link #next}. (Returns list size if the list
         * iterator is at the end of the list.)
         *
         * @return the index of the element that would be returned by a
         * subsequent call to {@code next}, or list size if the list
         * iterator is at the end of the list
         * <p>
         * <p>
         * 返回遊標後邊元素的索引位置
         */
        public int nextIndex() {
            return nextIndex;
        }

        /**
         * /**
         * Returns the index of the element that would be returned by a
         * subsequent call to {@link #previous}. (Returns -1 if the list
         * iterator is at the beginning of the list.)
         *
         * @return the index of the element that would be returned by a
         * subsequent call to {@code previous}, or -1 if the list
         * iterator is at the beginning of the list
         * <p>
         * 返回遊標前面元素的位置
         * 默認爲  -1
         * 如果木有元素  會拋出異常
         * NoSuchElementException    找不到元素
         */
        public int previousIndex() {
            return nextIndex - 1;
        }

        /**
         * Removes from the list the last element that was returned by {@link
         * #next} or {@link #previous} (optional operation).  This call can
         * only be made once per call to {@code next} or {@code previous}.
         * It can be made only if {@link #add} has not been
         * called after the last call to {@code next} or {@code previous}.
         *
         * @throws UnsupportedOperationException if the {@code remove}
         *                                       operation is not supported by this list iterator
         * @throws IllegalStateException         if neither {@code next} nor
         *                                       {@code previous} have been called, or {@code remove} or
         *                                       {@code add} have been called after the last call to
         *                                       {@code next} or {@code previous}
         * 從列表中刪除 next 或者 previous 方法返回的數據
         *  如果 未使用迭代中的 next 或者 previous  會拋出異常  IllegalStateException
         */
        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            unlink(lastReturned);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }

        /**
         * Replaces the last element returned by {@link #next} or
         * {@link #previous} with the specified element (optional operation).
         * This call can be made only if neither {@link #remove} nor {@link
         * #add} have been called after the last call to {@code next} or
         * {@code previous}.
         *
         * @param e the element with which to replace the last element returned by
         *          {@code next} or {@code previous}
         * @throws UnsupportedOperationException if the {@code set} operation
         *         is not supported by this list iterator
         * @throws ClassCastException if the class of the specified element
         *         prevents it from being added to this list
         * @throws IllegalArgumentException if some aspect of the specified
         *         element prevents it from being added to this list
         * @throws IllegalStateException if neither {@code next} nor
         *         {@code previous} have been called, or {@code remove} or
         *         {@code add} have been called after the last call to
         *         {@code next} or {@code previous}
         *
         * 給最後一次操作的值賦值
         *  只能在 迭代期間調用 ,並且沒有進行remove操作
         *
         */
        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.item = e;
        }

        public void add(E e) {
            checkForComodification();
            lastReturned = null;
            if (next == null)
                linkLast(e);
            else
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }
        //一個循環消費方法
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (modCount == expectedModCount && nextIndex < size) {
                action.accept(next.item);
                lastReturned = next;
                next = next.next;
                nextIndex++;
            }
            checkForComodification();
        }

        /**
         * 快速 - 失敗
         */
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }


    /**
     * Returns the (non-null) Node at the specified element index.
     * <p>
     * 返回指定位置的元素
     */
    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;
        }
    }

    /**
     * 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;
    }


    /**
     * Links e as last element.
     *  將元素e 添加到尾部節點
     */
    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++;
    }

    /**
     * Inserts element e before non-null Node succ.
     *  在非空的節點succ 前插入 e
     */
    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++;
    }


    /**
     * Inserts the specified element at the beginning of this list.
     * 將指定的元素添加到鏈表開始位置
     * @param e the element to add
     */
    @Override
    public void addFirst(E e) {
        linkFirst(e);
    }

    /**
     * Links e as first element.
     *  e 添加到開始
     */
    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }


    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #add}.
     *
     * @param e the element to add
     *
     *          將e 添加到結尾
     */
    @Override
    public void addLast(E e) {
        linkLast(e);
    }


    // Deque operations
    /**
     * Inserts the specified element at the front of this list.
     * 將 e 插入此列表的前面。
     * @param e the element to insert
     * @return {@code true} (as specified by {@link Deque#offerFirst})
     * @since 1.6
     */
    @Override
    public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
    /**
     * Inserts the specified element at the end of this list.
     *將 e 插入此列表的末尾
     * @param e the element to insert
     * @return {@code true} (as specified by {@link Deque#offerLast})
     * @since 1.6
     */
    @Override
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
    /**
     * Removes and returns the first element from this list.
     * 刪除鏈表開始節點
     * @return the first element from this list
     * @throws NoSuchElementException if this list is empty
     */
    @Override
    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 GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }
    @Override
    public E removeLast() {
        return null;
    }

    @Override
    public E pollFirst() {
        return null;
    }

    @Override
    public E pollLast() {
        return null;
    }

    @Override
    public E getFirst() {
        return null;
    }

    @Override
    public E getLast() {
        return null;
    }

    @Override
    public E peekFirst() {
        return null;
    }

    @Override
    public E peekLast() {
        return null;
    }

    @Override
    public boolean removeFirstOccurrence(Object o) {
        return false;
    }

    @Override
    public boolean removeLastOccurrence(Object o) {
        return false;
    }

    @Override
    public boolean offer(E e) {
        return false;
    }

    @Override
    public E remove() {
        return null;
    }

    @Override
    public E poll() {
        return null;
    }

    @Override
    public E element() {
        return null;
    }

    @Override
    public E peek() {
        return null;
    }

    @Override
    public void push(E e) {

    }

    @Override
    public E pop() {
        return null;
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public Iterator<E> descendingIterator() {
        return null;
    }

    /**
     * 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;
    }

    /**
     * Constructs an IndexOutOfBoundsException detail message.
     * Of the many possible refactorings of the error handling code,
     * this "outlining" performs best with both server and client VMs.
     */
    private String outOfBoundsMsg(int index) {
        return "Index: " + index + ", Size: " + size;
    }

    /**
     * 檢測索引位置是否存在
     */
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章