LinkedList数据结构源码分析


LinkedList 双向链表结构
总结
每个node都由前序节点node、当前元素值item和后续节点node组成
node=[prev_node,item,next_node]

注意这里是一个嵌套关系 即每个元素值都会存在3个地方
前一个节点都next属性中
当前节点的item属性中
后一个节点都prev属性中

下面分析源码组成部分

1. 列表首节点

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

2. 列表尾节点

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

3. 列表节点数量

    transient int size = 0;

4. 静态内部类 Node

用来存放节点信息 
Node 三部分组成
 1. 后续节点next 
 2. 前序prev
 3. 当前节点信息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;
    }
}

5. 接下里来分析下方法

1.add方法实现

    /**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

可以看到默认是添加到链表尾部Appends the specified element to the end of this list.

    /**
     * Links e as last element.
     */
    void linkLast(E e) {
        //最后一个节点赋值给变量l
        final Node<E> l = last;
        //初始化当前新增数据的节点 (前节点,当前节点元素,后续节点)
        final Node<E> newNode = new Node<>(l, e, null);
        // 当前节点是最后一个顾赋值给last
        last = newNode;
        //如果l == null 则说明当前列表为空列表  当前节点复制给首节点first
        if (l == null)
            first = newNode;
        // 如果l!=null则说明当前列表已有节点 把新增前的尾节点last的next节点指向新增节点 
        else
            l.next = newNode;
        size++;
        modCount++;
    }

2.remove() 删除节点方法

首先猜测下删除节点方法的实现
假设数据列表有a b c三个连续节点 现在要remove(b)
分析:
把节点a的后续指针a.next指向c节点
把节点c的前序指针c.prev指向c节点
把b节点的值制空 GC
size减1
修改次数加1 迭代器用

 /**
     * 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&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;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;
    }

再往下分析unlink(x)方法

 /**
     * Unlinks non-null node x.
     */
    E unlink(Node<E> x) {
        // assert x != null;
        // 要删除的节点赋值给element
        final E element = x.item;
        // 要删除的节点的后续节点赋值给next
        final Node<E> next = x.next;
        // 要删除的节点的前序节点赋值给prev
        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减1
        size--;
        //修改次数加1
        modCount++;
        return element;
    }

3.linkFirst添加首节点

只需要把首节点的前续指针指向新节点 新节点的后续指针指向当前首节点

    /**
     * Links e as first element.
     */
    private void linkFirst(E e)

4.linkLast添加尾部节点

把尾节点的后续指针指向新节点 
新节点的前续指针指向当前尾节点
    /**
     * Links e as last element.
     */
    void linkLast(E e) {

5.linkBefore插入节点在某个节点前

    /**
     * Inserts element e before non-null Node succ.
     */
    void linkBefore(E e, Node<E> succ) 

6.unlinkFirst移除首节点/尾节点

    /**
     * Unlinks non-null first node f.
     */
    private E unlinkFirst(Node<E> f)  {
    	//内部私有方法 上层调用已经做判断 所以下面断言是一定生效的
        // assert f == first && f != null;
        ...
     }  
     /**
     * Unlinks non-null last node l.
     */
    private E unlinkLast(Node<E> l) 

7.LinkedList 添加一个集合到LinkedList列表

    public boolean addAll(Collection<? extends E> c) {
     return addAll(size, c);
   }

这里其实就是循环♻️在当前列表添加一个个集合元素到队列尾部

自己觉得这块可以判断下类型 如果添加也是LinkedList可以做下判断
1、把添加列表的首节点和原来列表的尾节点建立关系
2、指定新的尾部节点
这样就不需要一个个元素循环了. 当然这样可能就不符合某些设计原则了

/**
     * 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;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

8.peek检索 但不移除表头节点 没有返回null

public E peek()  

9.element检索 但不移除表头节点

没有报错NoSuchElementException

public E element()  

10.poll检索 且移除表头节点 没有返回null

public E poll()  

11.remove 检索 且移除表头节点 没有报错NoSuchElementException

public E remove()

12.offer添加节点到列表尾部 返回true

public boolean offer(E e)

13.offerFirst在此列表的前面插入指定的元素。 返回true

public boolean offerFirst(E e)

14.offerLast在此列表的末尾插入指定的元素。返回true

public boolean offerLast(E e)

15.peekFirst检索但不删除此列表的第一个元素 返回列表的第一个元素或者返回null

public E peekFirst()

16.peekLast检索但不删除此列表的最后一个元素 返回列表的第后一个元素或者返回null

public E peekLast() 

17.pollFirst检索并删除此列表的第一个元素 返回列表的第一个元素或者返回null

public E pollFirst()

18. pollLast检索并删除此列表的最后一个元素

返回列表的最后一个元素或者返回null

public E pollLast()

19.push将元素推送到此列表表示的堆栈上。

换句话说,在这个列表的前面插入元素。同addFirst

public void push(E e)

20.pop从此列表表示的堆栈中弹出一个元素。

换句话说,删除并返回此列表的第一个元素。同removeFirst

    public E pop() 

21.removeFirstOccurrence删除此列表中第一次出现的指定元素

(从头到尾遍历列表时)。如果列表不包含该元素,则它不变。

    public boolean removeFirstOccurrence(Object o)

22.removeLastOccurrence删除此列表中指定元素的最后一次出现(从头到尾遍历列表时)。如果列表不包含该元素,则它不变。

        public boolean removeLastOccurrence(Object o)

23.set将此列表中指定位置的元素替换为指定元素。没有抛IndexOutOfBoundsException

  public E set(int index, E element) 

24. remove移除此列表中指定位置的元素。将任何后续元素向左移动(从它们的索引中减去 1)。返回从列表中删除的元素。没有抛IndexOutOfBoundsException

 public E remove(int index)

25.isElementIndex判断参数是否是现有元素的索引。

  private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

26.isPositionIndex迭代器或添加操作的时候判断参数是否是有效位置的索引。

  private boolean isPositionIndex(int index){
        return index >= 0 && index <= size;
    }

27.checkElementIndex检查索引 没有抛IndexOutOfBoundsException

    private void checkElementIndex(int index) 
  

28.indexOf返回此列表中指定元素第一次出现的索引,

如果此列表不包含该元素,则返回 -1。更正式地说,返回最低索引 {@code i} 使得 (o==null ? get(i)==null : o.equals(get(i))),如果有,则返回 -1是没有这样的索引。


    public int indexOf(Object o)

29.lastIndexOf返回此列表中指定元素最后一次出现的索引,

如果此列表不包含该元素,则返回 -1。更正式地说,返回最高索引 {@code i} 使得 (o==null ? get(i)==null : o.equals(get(i))),如果有,则返回 -1是没有这样的索引。


 public int lastIndexOf(Object o) 

30.listIterator返回此列表中元素的列表迭代器(以正确的顺序)迭代器

    public ListIterator<E> listIterator() 

31.clone返回此 {@code LinkedList} 的浅表副本。 (元素本身不会被克隆。)

 public Object clone()

32.toArray以正确的顺序(从第一个元素到最后一个元素)返回包含此列表中所有元素的数组。 返回的数据是单独开辟的空间

    public Object[] toArray() 

33.toArray 以正确的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组;

// 返回数组的运行时类型是指定数组的运行时类型。
// 如果列表适合指定的数组,则在其中返回。
// 否则,将使用指定数组的运行时类型和此列表的大小分配一个新数组

 public <T> T[] toArray(T[] a) 

34.writeObject重写了序列化和反序列化方法

//将此 {@code LinkedList} 实例的状态保存到流中(即序列化它)。

private void writeObject(java.io.ObjectOutputStream s)

35.readObject 从流中重构此 {@code LinkedList} 实例(即反序列化它)。

private void readObject(java.io.ObjectInputStream s)

6. 里面定义了三种迭代器,都是以内部类的方式实现,分别是:

DescendingIterator:倒序迭代器
一句话反着来就是了 别人正序我倒叙

 private class DescendingIterator implements Iterator<E> {
        private final ListItr itr = new ListItr(size());
        public boolean hasNext() {
            return itr.hasPrevious();
        }
        public E next() {
            return itr.previous();
        }
        public void remove() {
            itr.remove();
        }
    }

LLSpliterator:可分割迭代器
两个核心方法
迭代并执行给定的参数(参数=方法) forEachRemaining
分割 trySplit
⚠️这里的两个方法是有对应关系的 分割修改参数

这里有个知识点 java.util.function.Consumer 类的accept(T t); 对给定参数执行此操作。
也就是执行operation的方法作为参数传递 ,在需要的时候执行传递的方法
例如 list.spliterator().forEachRemaining(System.out::println); 就是传递了一个打印方法

  Consumer<? super E> action
  action.accept(e);

LinkedList的trySplit起始量尾1024

/** A customized variant of Spliterators.IteratorSpliterator */
    static final class LLSpliterator<E> implements Spliterator<E> {
    	//BATCH_UNIT = 1024
        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
        //MAX_BATCH = xxxx一个比较大的数
        static final int MAX_BATCH = 1 << 25;  // max batch array size;
        final LinkedList<E> list; // null OK unless traversed
        Node<E> current;      // current node; null until initialized
        int est;              // size estimate; -1 until first needed
        int expectedModCount; // initialized when est set
        int batch;            // batch size for splits

        LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
            this.list = list;
            this.est = est;
            this.expectedModCount = expectedModCount;
        }

        final int getEst() {
            int s; // force initialization
            final LinkedList<E> lst;
            if ((s = est) < 0) {
                if ((lst = list) == null)
                    s = est = 0;
                else {
                    expectedModCount = lst.modCount;
                    current = lst.first;
                    s = est = lst.size;
                }
            }
            return s;
        }

        public long estimateSize() { return (long) getEst(); }

        public Spliterator<E> trySplit() {
            Node<E> p;
            int s = getEst();
            if (s > 1 && (p = current) != null) {
            //这里达到1024切小于MAX_BATCH才会分隔
                int n = batch + BATCH_UNIT;
                if (n > s)
                    n = s;
                if (n > MAX_BATCH)
                    n = MAX_BATCH;
                Object[] a = new Object[n];
                int j = 0;
                do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
                current = p;
                batch = j;
                //剩余量尾总量减去本次分割量
                est = s - j;
                return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
            }
            return null;
        }
       //循环执行给定的方法(正序)
        public void forEachRemaining(Consumer<? super E> action) {
            Node<E> p; int n;
            if (action == null) throw new NullPointerException();
            if ((n = getEst()) > 0 && (p = current) != null) {
                current = null;
                est = 0;
                do {
                    E e = p.item;
                    p = p.next;
                    action.accept(e);
                } while (p != null && --n > 0);
            }
            if (list.modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
		//单个执行给定的方法action
        public boolean tryAdvance(Consumer<? super E> action) {
            Node<E> p;
            if (action == null) throw new NullPointerException();
            if (getEst() > 0 && (p = current) != null) {
                --est;
                E e = p.item;
                current = p.next;
                action.accept(e);
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }

        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

ListItr:列表的经典迭代器

这个就是基础的迭代器Iterator的实现,方便列表进行便利

private int expectedModCount = modCount;
继承迭代器增加一个功能 -默认记录了修改次数,保障迭代过程的安全性

private class ListItr implements ListIterator<E> {
        //上一次迭代返回的节点 
        private Node<E> lastReturned;
        // lastReturned的正序下一个节点 
        private Node<E> next;
         // lastReturned的正序下一个节点对索引 
        private int nextIndex;
        //预期修改次数和实际修改次数 
        private int expectedModCount = modCount;

        ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }

        public boolean hasNext() {
            return nextIndex < size;
        }

        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();
			//
            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }

        public boolean hasPrevious() {
            return nextIndex > 0;
        }

        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

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

        public int nextIndex() {
            return nextIndex;
        }

        public int previousIndex() {
            return nextIndex - 1;
        }

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

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

【作者简介】:
里奥学JAVA,公众号【里奥学JAVA】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界希望一切都很快,更快,但是我希望自己能走好每一步,写好每一篇文章,期待和你们一起交流。

此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者核实删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值