肯定是有错的。。。说来惭愧,有些方法至今没有用过,比起ArrayList,好像LinkedList没有提供关于子表的方法。
(没有标号怎么实现截取,在Node里面再加一个标号吗哈哈哈哈)
package java.util;
import java.util.function.Consumer;
public class LinkedList<E>
extends AbstractSequentialList<E>
/*双链表,在{1}处有提到原因,且不带头结点,原因在{2}处*/
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//记录链表中元素的个数
//size对于链表的实现并不是必须的
//用transient修饰
transient int size = 0;
//存储头结点
//利用了transient修饰
transient Node<E> first;
//节点类的定义:(可见这是一个双链表)
/*{1}:
public 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;
}
}
*/
//存储最后一个节点
//利用了transient修饰
transient Node<E> last;
//创建一个空的链表
//从构造方法可见,该链表不带头结点
//{2}:
public LinkedList() {
}
//根据Collection创建一个双链表
//顺序同Iterator遍历的顺序
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);//添加,将在{3}处说明
}
//{6}
/*添加e作为第一个节点*/
/*
我的话可能就是这样写:
Node<E> q = new Node(null, e, first);
if (first != null) //非空
last = q;
else
first.prev = q;
first = q;
*/
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++;//将size + 1
modCount++;//将modCount + 1
}
//{7}
/*尾插入*/
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++;//size + 1
modCount++;//modCount + 1
}
/*如果让我写:
分析情况如下:
1.表空(不可能)
2.表非空。头插---调用头插
3.表非空。中间插入---写中间插入代码
4.表非空。尾插---不可能(因为不是循环链表)
关于第四点我想说的是:循环链表只有中间插入的概念,控制相对方便。
而且尾插的话,直接插头结点之前不就行了。
实际上设置头结点就是这个原因(对于某些链表)
可以将头插代码和中间插入代码合并,且中间插入代码本来就可以和尾插入代码合并
而空表插入,由于有了一个头结点的存在,而变成了尾插。
使三种插入情况相同(实际上应该是四种)。
if (succ.prev == null)
linkFirst(e);
else {
Node<E> q = new Node(succ.prev, e, succ);
succ.prev.next = q;
succ.prev = q;
}
链表很基础,但是容易迷
凡是引用类型的变量,其最后一个点前面的都是要被运算出来的
最后一个‘.’之后的才是赋值的对象
*/
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev;//succ为空第一句开始就报错
final Node<E> newNode = new Node<>(pred, e, succ);//创建新节点
succ.prev = newNode;//succ前一个 赋值为 新节点
if (pred == null)//如果succ原先的前一个为空(说明succ是第一个节点)
first = newNode;//相当于头插
else
pred.next = newNode;//不为空,succ前一个的next赋值为新节点
size++;//size + 1
modCount++;//modCount + 1
}
//{4}
//实际上的作用是将f和f之前的节点删除
//(但是size--就说明只能是头结点)
private E unlinkFirst(Node<E> f) {
final E element = f.item;//将f的item域暂存
final Node<E> next = f.next;//将f后一个节点暂存
f.item = null;//f.item赋值null
f.next = null;
//上面两行是为了gc
first = next;//first赋值next(看到这里我才懂方法的意思)
if (next == null)//如果next是null(说明链表中只有f一个节点)
last = null;
else
next.prev = null;//不为空,新的第一节点是头结点,所以prev域为空
size--;//大小 - 1
modCount++;//modCount + 1
return element;//将移除的元素返回
}
//{5}
//将l在内的之后的节点统统删除,返回l的item域
//(但是size--就能说明只能是尾结点,不然size出错)
private E unlinkLast(Node<E> l) {
final E element = l.item;//暂存最后一个节点
final Node<E> prev = l.prev;//暂存将来的最后一个节点
l.item = null;//触发gc
l.prev = null;//触发gc
last = prev;//last指针指向prev
if (prev == null)//如果只有一个节点
first = null;//移除之后first也是null了
else
prev.next = null;//将倒数第二个节点指向最后一个节点的引用断开
size--;//size - 1
modCount++;//modCount + 1
return element;//返回暂存节点
}
//{9}
//将节点从这个链表中删除
//为什么不先直接判断然后调用其他头删尾删的方法呢?
//就因为三种操作有共同性?
E unlink(Node<E> x) {
final E element = x.item;//将x的item域暂存
final Node<E> next = x.next;//将x的下一个暂存
final Node<E> prev = x.prev;//将x的上一个暂存
if (prev == null) {//如果是第一个节点
first = next;//更改first的值
} else {//如果不是
prev.next = next;//将前一个的next域赋值为x的后一个
x.prev = null;//将x的prev域赋值为null
}
if (next == null) {//如果是最后一个节点
last = prev;//更改last的值
} else {
next.prev = prev;//将后一个的prev域赋值为x的前一个
x.next = null;//将x的next域赋值为null
}
x.item = null;//将x的item域赋值为null
size--;//size - 1
modCount++;//modCount + 1
return element;//返回
}
//将第一个节点的item域返回
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
//将最后一个节点的item域返回
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
//将第一个节点的值移除之后返回
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);//调用了{4}处定义的方法
//作用是将第一个节点移除并返回其item域
}
//将最后一个节点移除并返回
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);//同上,调用{5}处方法
}
//头插
public void addFirst(E e) {
linkFirst(e);//调用{6}
}
//尾插
public void addLast(E e) {
linkLast(e);//调用{7}
}
//是否包含o
public boolean contains(Object o) {
return indexOf(o) != -1;//调用{8}
}
//返回元素个数,size的存在使得本方法不必遍历,效率得到提高
public int size() {
return size;
}
//addLast改头换面版本,只不过是增加了返回值...
public boolean add(E e) {
linkLast(e);
return true;
}
//和indexOf(Object o)方法类似,找到节点之后删除
//注:indexOf方法在{8}处
//将第一次出现o的节点移除
//存在返回true,不存在返回false(应该是操作成功返回的)
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);//调用{9}
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);//调用{9}
return true;
}
}
}
return false;
}
//{3}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);//见{10}
}
//{10}
//从指定值开始插入c
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);//见{11}
//--提取c中的数据
Object[] a = c.toArray();//将c转变成为数组
int numNew = a.length;//新插入元素的个数
if (numNew == 0)//如果插入元素个数为0
return false;
//初始化前置节点和后置节点
Node<E> pred, succ;
if (index == size) {//尾插
succ = null;//后置节点为空(因为最后一个后面没有了)
pred = last;//前驱节点为最后一个节点
} else {
//查找到第index个节点
succ = node(index);//见{13}
pred = succ.prev;
}
for (Object o : a) {//开始进行遍历
@SuppressWarnings("unchecked") E e = (E) o;//暂存
Node<E> newNode = new Node<>(pred, e, null);//创建新节点
if (pred == null)//如果是从0开始,即index == 0或者空表
first = newNode;//更改第一个的值
else
pred.next = newNode;//前一个的next域变为创建节点
pred = newNode;//因为要从新节点开始插入,所以前置节点变成新创建的节点
}
//等到所有的元素都添加完毕之后
if (succ == null) {//如果后置节点是空
last = pred;//将尾结点置为添加的最后一个节点
} else {//若不是尾插
pred.next = succ;//最后一个节点的next域赋值为后置节点
succ.prev = pred;//后置节点的prev域赋值为最后一个插入的节点
}
size += numNew;//容量增加
modCount++;//其实我觉得modCount应该加上numNew
return true;//返回操作成功
}
public void clear() {
//用于触发gc
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++;
}
// 指定位置访问
// Positional Access Operations
//喜闻乐见的get方法
public E get(int index) {
checkElementIndex(index);//见{14}
//下标检查
return node(index).item;//查询之后返回
}
public E set(int index, E element) {
checkElementIndex(index);//下标检查
Node<E> x = node(index);//查询
E oldVal = x.item;//暂存旧值
x.item = element;//赋新值
return oldVal;//返回旧值
}
public void add(int index, E element) {
checkPositionIndex(index);//下标检查
//要求0-size
if (index == size)//如果是尾插
linkLast(element);//调用尾插
else//一般插入
linkBefore(element, node(index));
//在这个节点之前插入,作为第index个节点
}
//将指定位置的删除
public E remove(int index) {
checkElementIndex(index);//下标检查
return unlink(node(index));//将index的节点删除
}
//{15}
//下标对应的值在list中是否存在
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
//告知我们这个下标是否对于迭代器和添加操作是安全的
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
//返回一个信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
//{14}
//一个检查方法
private void checkElementIndex(int index) {
if (!isElementIndex(index))//见{15}
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//{11}
//emmm一个下标检查方法
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))//见{12}
//检查下标是否对于迭代器和添加操作是有效的
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//{13}
//实际上相当于一个内部的get方法
Node<E> node(int index) {
if (index < (size >> 1)) {//如果index比较靠前
Node<E> x = first;//从前向后进行查找
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;//如果index比较靠后,从后向前进行查找
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;//返回顺序查找的结果
}
}
// Search Operations
//返回o第一次出现的下标{8}
public int indexOf(Object o) {
int index = 0;//从0开始
//之后的判断是不是似曾相识?
//哈哈~在ArrayList中就是这么处理的~
if (o == null) {
for (Node<E> x = first; x != null; x = x.next, /*index ++*/) {
//元素从0个开始,下标也是从0开始。
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;
}
//返回最后一个出现o的下标
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {//同ArrayList中的控制,避免空指针异常
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;//空指针
}
//和上面不同的是,如果链表是空的,将会抛出NoSuchElementException
public E element() {
return getFirst();
}
//第一个返回并删除
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//和element方法差不多,没有元素抛出异常
public E remove() {
return removeFirst();
}
//不解释
public boolean offer(E e) {
return add(e);
}
// Deque operations
//头插
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//头插
public boolean offerLast(E e) {
addLast(e);
return true;
}
//返回第一个
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 E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//返回最后一个并移除
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
//头插
public void push(E e) {
addFirst(e);
}
//尾删
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;
}
/*
和ArrayList一样,都是在接口中给出定义,
之后在具体实现的数据结构的内部类中给出实现。
*/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);//下标检查
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned;//刚刚返回的节点(或者说是将要进行操作的节点)
private Node<E> next;//将要返回的节点
private int nextIndex;//将要返回的节点的下标
private int expectedModCount = modCount;//期望的modCount值
ListItr(int index) {//构造方法
next = (index == size) ? null : node(index);
//如果不加上上面的而一句,index = size的情况就覆盖不到
nextIndex = index;//下一个将要返回的下标定为index
}
public boolean hasNext() {//是否有下一个
return nextIndex < size;
}
public E next() {//将当前next指向的节点返回
checkForComodification();//检查list是否进行了结构化更改
if (!hasNext())//有没有下一个,实则相当于下标检查(内部类中的下标检查)
throw new NoSuchElementException();
//这几句就没有什么好说的了
lastReturned = next;//将表示刚刚返回的lastReturned赋值为next
next = next.next;
nextIndex++;
return lastReturned.item;
}
public boolean hasPrevious() {//返回是否有前驱节点
return nextIndex > 0;//感觉用 next.prev != null 也行
}
public E previous() {//返回前一个
checkForComodification();//更改检查
if (!hasPrevious())//是否有前一个
throw new NoSuchElementException();
/*这里首先考虑next的取值,next可能由于遍历了list而指向了最后一个的后一个*/
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)//如果之前返回的是null
throw new IllegalStateException();
//不允许创建之后没有进行任何返回就开始修改表?
Node<E> lastNext = lastReturned.next;//上一次返回的下一个暂存
unlink(lastReturned);//将上一次返回的节点删除
if (next == lastReturned)
//如果将要进行操作的节点和上一次返回的节点一样的话
//这种情况主要针对之前调用了previous方法的情况
next = lastNext;//将要操作的节点赋值成为删除节点的下一个
else//这种就是一般的调用了next方法的
nextIndex--;如果不是,就将下标进行改变
lastReturned = null;//最后一次返回的值置为空
//因为这个节点不能删两次(实际上删除的永远应该是已经遍历或者说是访问到的节点)
expectedModCount++;//将期望的modCount + 1
}
public void set(E e) {//
if (lastReturned == null)//如果刚刚经历过删除或者Iterator刚刚进行创建
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++;//下一个的下标+1
expectedModCount++;//修改modCount
}
//和ArrayList中相同,都是对于每一个值进行同样的操作
//确切的说,是对于还没有访问过的值进行已经定义的相同操作
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);//判空
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);//进行操作
lastReturned = next;//相当于遍历,修改lastReturned的值
next = next.next;//将next的值改变
nextIndex++;//nextIndex值修改
}
checkForComodification();//检查修改
}
//检查修改方法
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
//这里可以看到Node的定义
//双节点
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;
}
}
/**
* @since 1.6
*/
//从1.6就开始有的一个类
//用于从另一个方向遍历
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}
//倒序Iterator
//相对于之前Itr的实现,挺有意思的
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();
}
}
//克隆方法
@SuppressWarnings("unchecked")
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
//浅克隆
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
//如果你好奇为什么first并没有初始化,看看add方法中做了什么就知道了
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
//转化成为数组
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
//
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)//如果a的长度比较小,创建一个新的数组
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;//将i的值置为0
Object[] result = a;
//复制
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)//用于判断长度用的
a[size] = null;
return a;//返回结果
}
//好神奇的位置...
private static final long serialVersionUID = 876323262645176354L;
//就是...将他存起来
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
//将类中除了static和transient修饰的变量存起来
//只能在writeObject中调用
s.defaultWriteObject();
//你懂得
s.writeInt(size);
//依旧是只存元素
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}
//读
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
//和上面的正好的反过来的,不多解释了
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
linkLast((E)s.readObject());
}
//可分割的Iterator
@Override
public Spliterator<E> spliterator() {
return new LLSpliterator<E>(this, -1, 0);
}
//并行迭代器
static final class LLSpliterator<E> implements Spliterator<E> {
static final int BATCH_UNIT = 1 << 10; //一批增长的大小
static final int MAX_BATCH = 1 << 25; //一批增长的最大大小
final LinkedList<E> list; //迭代对象
Node<E> current; //当前节点
int est; //估算大小(你当成实际的看也行)
int expectedModCount; //期望的修改值
int batch; //一批增长的粒度
LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
this.list = list;
this.est = est;
this.expectedModCount = expectedModCount;
}
//初始化current、expectedModCount和est并返回est
final int getEst() {
int s; // force initialization(需要我们强制指定?)
final LinkedList<E> lst;
if ((s = est) < 0) {//如果est小于0(没有调用过这个方法)
if ((lst = list) == null)//如果传入list为空
s = est = 0;
else {//如果list不为空
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) {//current是第一个节点,证明当前值不为空
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();
}
//处理一个(就像Iterator修改一样)
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;
}
}
}