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));
    }
}

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