目录
一、分析
- 环境:JDK1.8
- LinkedList 双向链表,支持null元素
二、变量
/** * 不被序列化的大小 */ transient int size = 0; /** * 指向第一个元素节点 */ transient Node<E> first; /** * 指向最后一个元素节点 */ transient Node<E> last;
First Node,Last Node,首尾都有指针,便于向前、向后遍历
三、方法
1.构造函数
/** * 空构造函数 */ public LinkedList() { } /** * 指定的集合构造链表 */ public LinkedList(Collection<? extends E> c) { this(); // 新增所有的元素 addAll(c); }
2.私有、默认方法
/** * 指定元素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 // 如果当前的首节点不为空,那么将当前首节点的前置节点从null->新节点 f.prev = newNode; // 元素数+1 size++; modCount++; } /** * 设定元素e为最后一个元素 */ void linkLast(E e) { // 获取当前的尾节点 final Node<E> l = last; // 以传入的元素创建一个新的节点,新节点的后置为null,新节点的前置为当前的尾节点 final Node<E> newNode = new Node<>(l, e, null); // 将新节点置为尾节点 last = newNode; if (l == null) // 如果当前的尾节点就是空,那么就是列表为空,首节点置为指向当前节点 first = newNode; else // 如果当前的尾节点不为空,那么将当前的尾节点后置节点从null->新节点 l.next = newNode; // 元素数+1 size++; modCount++; }
/** * 在元素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++; } /** * 删除非空的第一个元素 */ 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) // 如果下一个节点为null,则当前为空列表,置空最后一个节点 last = null; else // 如果下一个节点不为null,则将下一个节点的前指针置空 next.prev = null; size--; modCount++; return element; } /** * 删除非空的最后一个元素 */ private E unlinkLast(Node<E> l) { // assert l == last && l != null; // 要删除的元素 final E element = l.item; // 获取上一个元素节点 final Node<E> prev = l.prev; // 清空当前节点,便于GC回收 l.item = null; l.prev = null; // help GC // 尾指针指向上一个节点 last = prev; if (prev == null) // 如果上一个节点为空,那么列表就为空了,将首节点置空 first = null; else // 如果上一个节点不为空,那么将上一个节点的后置指针清空,作为尾节点 prev.next = null; size--; modCount++; return element; } /** * 删除指定的非空元素 */ 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; }
// 核查 索引 是否有效 private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
/** * 判断 指定的索引参数,在迭代器或者添加操作里是否有效 */ private boolean isPositionIndex(int index) { return index >= 0 && index <= size; }
// 核查 元素 索引 private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
/** * 判断 指定元素索引是否,拥有有效元素 */ private boolean isElementIndex(int index) { return index >= 0 && index < size; }
/** * 构造数组越界异常的详细信息 */ private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; }/** * 返回指定索引位置的非空节点 */ 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; } }
3.共有方法
3.1.查询
/** * 返回列表中的第一个元素 */ public E getFirst() { // 获取first Node final Node<E> f = first; if (f == null) throw new NoSuchElementException(); // 返回Node的元素值 return f.item; } /** * 返回列表中的最后一个元素 */ public E getLast() { // 获取Last Node final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; }
/** * 返回列表的元素个数 */ public int size() { return size; }
/** * 判断 指定的元素是否存在于列表 */ public boolean contains(Object o) { return indexOf(o) != -1; }
/** * 从First -> Last 遍历 * 返回 指定元素 第一次出现在列表中的索引 * 如果元素不存在:返回 -1 * 支持查null元素 */ public int indexOf(Object o) { // 索引从0开始 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; } /** * 从Last -> First 遍历 * 返回 指定元素 最后一次出现在列表中的索引 * 如果元素不存在:返回 -1 * 支持查null元素 */ public int lastIndexOf(Object o) { // 索引位置为实际元素大小 int index = size; // 判空,支持null定位 if (o == null) { // 从Last node开始遍历 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 operations. /** * 检索出 第一个元素 * 首元素不会被移除 */ public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; } /** * 检索出 第一个元素 * 首元素不会被移除 * * 区别:与peek()方法相比,会抛出 列表为空的异常 * @throws NoSuchElementException if this list is empty */ public E element() { return getFirst(); }
/** * 返回指定索引位置的元素 */ public E get(int index) { // 核查索引是否有效 checkElementIndex(index); // 返回 非空节点值 return node(index).item; }
/** * 检索 列表首个元素,不删除元素 */ public E peekFirst() { final Node<E> f = first; return (f == null) ? null : f.item; } /** * 检索 列表尾部元素,不删除元素 */ public E peekLast() { final Node<E> l = last; return (l == null) ? null : l.item; }/** * 双向遍历器 */ public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); }/** * 递减迭代器 * @since 1.6 */ public Iterator<E> descendingIterator() { return new DescendingIterator(); }
3.2.新增
/** * 添加元素到列表的尾部 */ public boolean add(E e) { linkLast(e); return true; }
/** * 设定指定的元素为列表的首节点 * * @param e the element to add */ public void addFirst(E e) { linkFirst(e); }
/** * 设定指定的元素为列表的尾节点 */ public void addLast(E e) { linkLast(e); }
/** * 指定的元素添加到链表的尾部 * @since 1.5 */ public boolean offer(E e) { return add(e); }
/** * 将指定集合元素 全部添加到列表的尾部 * note:如果在添加的过程中,指定集合被修改了 */ public boolean addAll(Collection<? extends E> c) { return addAll(size, c); }
/** * 从指定位置开始,插入指定集合的元素 * * @param index 首个插入元素的索引 * @param c 指定的集合 */ public boolean addAll(int index, Collection<? extends E> c) { // 核查索引 checkPositionIndex(index); // 集合转数组 Object[] a = c.toArray(); // 指定数组长度 int numNew = a.length; if (numNew == 0) return false; // pred : 前一个索引;succ:当前索引; 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; // 创建一个节点:前置为上一个元素,后置为null Node<E> newNode = new Node<>(pred, e, null); if (pred == null) // 如果前置索引为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; }
/** * 在指定索引位置,新增指定的元素 */ public void add(int index, E element) { checkPositionIndex(index); if (index == size) // 如果索引为最后一个节点,链接为最后一个节点 linkLast(element); else // 在指定索引节点前,新增指定元素节点 linkBefore(element, node(index)); }
/** * 在列表首部新增元素 */ public boolean offerFirst(E e) { addFirst(e); return true; } /** * 在列表尾部新增元素 */ public boolean offerLast(E e) { addLast(e); return true; }public void push(E e) { addFirst(e); }
3.3.删除
/** * 删除 列表中 第一次出现指定元素 * 支持:null元素 * 原理:修改当前元素节点的前置和后置节点的指针 */ public boolean remove(Object o) { // 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; }
/** * 删除并返回 第一个元素 */ 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); }
/** * 检索列表首元素,并删除首个元素 */ public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); } /** * 检索列表首元素,并删除首个元素 * 与poll()方法 区别: * 列表为空,抛异常 * @throws NoSuchElementException if this list is empty * @since 1.5 */ public E remove() { return removeFirst(); }
/** * 删除集合里的所有元素 * 从First->Last遍历,置空所有节点指针和值,供GC回收 */ 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 Iterator for (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++; }
/** * 删除指定索引位置的节点 */ public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
/** * 检索并删除首个元素 */ public E pollFirst() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); }public E pop() { return removeFirst(); }/** * 删除 首次出现的元素 */ public boolean removeFirstOccurrence(Object o) { return remove(o); } /** * 删除 最后一次出现的元素 */ 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; }
3.4.修改
/** * 替换指定位置,为指定的元素 * 返回旧的元素值 */ public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
四、内部类
/** * 元素节点单位 * @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; } } /** * 双向迭代器 */ private class ListItr implements ListIterator<E> { private Node<E> lastReturned; private Node<E> next; 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(); } } /** * 适配提供 从后往前 迭代器 */ 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(); } } /** LinkedList实现的分割器 */ static final class LLSpliterator<E> implements Spliterator<E> { static final int BATCH_UNIT = 1 << 10; // batch array size increment 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) { 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(); } 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; } }
五、总结
根据源码和经验总结,后期更新
-
实现原理
-
应用场景
-
工作经验