/** * Links e as last element. 翻译 : 链接e作为最后一个元素。 先对last赋值给 Node<E> l , 然后调用new Node<>(l,e,null);传入进去的上个节点,也就是l,上次保存的尾部节点,也就是从倒数第一变为了倒数二,这样理解。然后此时的newNode就是尾节点了,然后赋值给last,因为last每次记录的都是尾节点. if else 中是对之前的尾节点进行判断,如果是null的话,说明此时就是添加的第一个元素,first也赋值给newNode,否则的话,l.next 和 尾节点进行关联。 size 长度加一 */ voidlinkLast(E e) { final Node<E> l = last; final Node<E> newNode = newNode<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
if (index < (size >> 1)) { Node<E> x = first; for (inti=0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (inti= size - 1; i > index; i--) x = x.prev; return x; } }
/** 获取节点的上个节点赋值给pred,其实类似于pred这种,都是用于变量替换创建出来的. 上一个节点,当前值e,succ节点来new一个新的节点出来. succ.prev 指向当前new出来的节点 对pred判断是否是null,如果是null的话,就说明是第一个值,否则就是赋值上pred个节点的next ,size ++ 就是对长度 ++ */ voidlinkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = newNode<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
代码逻辑如下图:
addFirst(E e)头插入
将值插入到头部
publicvoidaddFirst(E e) { linkFirst(e); }
/** 先将first 赋值给 f , 根据传入进来的值e 和 下一个节点f(前一个头节点),new一个新的newNode节点出来,first指向newNode.如果f是null的话就说明是初始化,如果不是null的话,f的上一个节点指向newNode,刚刚程序newNode出来的.就完成了头节点的插入 */ privatevoidlinkFirst(E e) { final Node<E> f = first; final Node<E> newNode = newNode<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
代码逻辑如下
addLast(E)尾插入
与头节点相似,也是利用变量last来实现尾部插入
可参考上面的头插入图,也就是将头的判断和指针的指向倒过来,换成尾就是的了
publicvoidaddLast(E e) { linkLast(e); }
voidlinkLast(E e) { final Node<E> l = last; final Node<E> newNode = newNode<>(l, e, null); last = newNode; // 如果尾节点没有,则说明原的linkedList是没有元素的 if (l == null) first = newNode; else // 原来的last的next指向新new出来的node l.next = newNode; // 长度和迭代的标记都+1 size++; modCount++; }
public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); }
/** 取出 f 的item,节点对应的值和 f的next个节点,如果下个节点是null的话,就说明是没有值的,如果不为null的话,说将next的上一个节点prev指向null,因为头节点的prev和尾节点的next都是null来进行区分。 */ private E unlinkFirst(Node<E> f) { // assert f == first && f != null; finalEelement= 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; }
remove()方法
移出第一个元素,也就是和 poll 的逻辑是一致的
public E removeFirst() { final Node<E> f = first; if (f == null) thrownewNoSuchElementException(); return unlinkFirst(f); }
public E remove(int index) { checkElementIndex(index); return unlink(node(index)); }
/** 这里获取出节点的 next 和 prev方法. 该节点的上一个节点(prev)的next需要指向指向该节点的下个节点(next),该节点的下一个节点和prev的操作是相反的,因为这样的话,就删除了该节点,并且上一个节点和下一个节点关联起来了. */ E unlink(Node<E> x) { // assert x != null; finalEelement= 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; }
publicbooleanremove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); returntrue; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); returntrue; } } } returnfalse; }