JDK源码之LinkedList

下文带/**/为源码注释//为个人注释源代码使用这个颜色

Node对象存储元素和元素左右数据的指针
add(e),我将我自己添加到上一个元素的Next

addFirst(e)替换链表头
addLast(e)替换链表尾
addadd(index,ele)---linkLast or linkBefore

getFirst();getLast();效率最高的两个获取
为什么说链表获取元素慢!
set(index,ele)更新元素同样需要遍历集合!
removeFirst删除并重新赋值first
removeLast删除并重新赋值Last
remove(index)四种删除情况!
remove(obj)删除指定元素的两种情况

Node对象存储元素和元素左右数据的指针

/*构建一个空列表*/

//无参构造器

public LinkedList() {}

//将要添加的元素放到Node对象中的item属性中。

//多个Node对象构成一个链表,对象中持有下一个

//和上一个Node对象

private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {

//当前Node对象
this.item = element;

//下一个
this.next = next;

//上一个
this.prev = prev;
}
}

/**指向最后一个节点的指针**/

transient Node<E> last;//LinkedList的成员变量

/*指向第一个节点的指针*/

transient Node<E> first;//LinkedList的成员变量

/*该列表被修改的次数*/

protected transient int modCount = 0;//LinkedList的成员变量

//当前集合的元素总个数

transient int size = 0;//LinkedList的成员变量

add(e),我将我自己添加到上一个元素的Next

/*将指定的元素追加到列表的末尾。*/

//添加元素

public boolean add(E e) {
linkLast(e);
return true;
}

/*e作为最后一个元素。*/

void linkLast(E e) {

//先拿到列表中最后一个元素,列表是第一次添加元素是没有的
final Node<E> l = last;

//创建Node对象,将最后一个元素当成Node的prev

//传入的元素是当前Node元素,下一个不传
final Node<E> newNode = new Node<>(l, e, null);

//当前创建的Node成为最后一个元素,也就是下一个Node的prev
last = newNode;

//如果上一个为null,当链表是第一次添加元素这个是null
if (l == null)

//将新增的Node赋值到第一个节点的指向,现在来看这个值只会被赋值一次?
first = newNode;
else

//如果last不是null则表示列表内已经有元素

//一个新增加的元素其实是一个Node但是这个Node是没有next的

//这个赋值代表着,如果链表内有元素,将这个新创建的Node赋值

//给上一个Node的next
l.next = newNode;

size++;
modCount++;
}

addFirst(e)替换链表头

/*在列表的开头插入指定的元素。*/

public void addFirst(E e) {
linkFirst(e);
}

/*e作为第一个元素。*/

private void linkFirst(E e) {

//拿到first元素
final Node<E> f = first;

//创建新Node它的first是null,next是原来的first
final Node<E> newNode = new Node<>(null, e, f);

//将first指针指向新Node
first = newNode;

//如果f是null表示之前没有元素
if (f == null)

//则新添加的node同时也是last
last = newNode;
else//如果f不是null

//将新添加的Node指针赋值给原有first的prev

f.prev = newNode;

//计数器
size++;
modCount++;
}

addLast(e)替换链表尾

/*将指定的元素追加到列表的末尾。*/

public void addLast(E e) {
linkLast(e);
}

/*e作为最后一个元素。*/

void linkLast(E e) {

//拿到原来的last
final Node<E> l = last;

//创建新的Node它的prev是原来的last阿德next是null
final Node<E> newNode = new Node<>(l, e, null);

//将新创建的Node赋值给last
last = newNode;

//如果l==null表示原来没有元素
if (l == null)

//此时只有新增加的元素,所以它也是first
first = newNode;
else

//如果原来有元素,则原来的last的next为新创建的Node
l.next = newNode;

//计数器
size++;
modCount++;
}

addadd(index,ele)---linkLast or linkBefore

/*

在列表的指定位置插入指定的元素。将元素当前的位置

(如果有的话)和后续的元素向右移动(在它们的索引中添加一个)。

*/

public void add(int index, E element) {

//index只能大于=0或者小于=size,否则异常

checkPositionIndex(index);

if (index == size)

//如果index等于size表示当前做的是追加操作
linkLast(element);
else

//那这里应该是包含0的情况其实就是linkFirst()

//不清楚为啥不判断下。

//首先获取下标Node
linkBefore(element, node(index));
}

private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/*告知参数是否是迭代器或添加操作的有效位置的索引。*/

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

/*将元素e插入到非空节点succ之前。*/

void linkBefore(E e, Node<E> succ) {
// assert succ != null;

//拿到下标Node的prev

final Node<E> pred = succ.prev;

//创建新的Node它的prev是succ Node的prev,它的next是succ

//简单描述新创建的元素在index的前边
final Node<E> newNode = new Node<>(pred, e, succ);

//index Node的prev指针变成了新创建的Node
succ.prev = newNode;

//原来的Node的prev如果是null表示它原来是第一个元素

//那就把新创建的Node赋值到first
if (pred == null)
first = newNode;

//原来的Node不是first则将原有Node的prev的next赋值成newNode
else
pred.next = newNode;

//计数器
size++;
modCount++;
}

getFirst();getLast();效率最高的两个获取

//第一个Node创建后,last和first都是Node1。第二个Node创建后last是Node2,还是firstNode1。

//拿到Node后获取成员item。

/*返回列表中的第一个元素。*/

public E getFirst() {

final Node<E> f = first;

if (f == null)

throw new NoSuchElementException();

return f.item;

}

/*返回列表中的最后一个元素*/

public E getLast() {

final Node<E> l = last;

if (l == null)

throw new NoSuchElementException();

return l.item;

}

为什么说链表获取元素慢!

/*返回列表中指定位置的元素。*/

public E get(int index) {

//判断index是否合法

checkElementIndex(index);

//这是个重点方法。

return node(index).item;

}

private void checkElementIndex(int index) {

if (!isElementIndex(index))

 throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

}

/**告知参数是否为现有元素的索引。**/

private boolean isElementIndex(int index) {

//要查询的index在0和size-1之间则返回true

return index >= 0 && index < size;

}

/*返回指定元素索引处的(非空)节点。*/

Node<E> node(int index) {

//如果要查询的index小于当前size/2

if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//如果要查询的index大于当前size/2
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}

//这里假设LinkedList元素总个数为100,当前查询的index为49则100/2=50

//49<50,先获取集合内第一个Node,然后从0开始,每次都取Node的Next

//也就是Next代表的Node。需要循环49次才能拿到index为49的元素。

//如果当前元素为100,当前查询的index为50,则从99开始,往后循环查询

//需要循环48次。最快的两种情况是要查询第0号下标则第一个循环不满足直接

//返回first或者要查询99号下标不满足第二个循环直接返回last。但是这两

//中情况使用getFirst()或者getLast()是最快的。

set(index,ele)更新元素同样需要遍历集合!

/*将列表中指定位置的元素替换为指定元素。*/

public E set(int index, E element) {

//检验下标是否合格,上边说过这个方法。
checkElementIndex(index);

//同样需要找到对应的Node,上边说过这个方法。
Node<E> x = node(index);

//获取老的元素
E oldVal = x.item;

//新的元素替换老的元素
x.item = element;

//返回被替换的元素
return oldVal;
}

removeFirst删除并重新赋值first

/*删除并返回列表中的第一个元素。*/

public E removeFirst() {

//获取first元素
final Node<E> f = first;
if (f == null)

//如果是null表示当前集合没有元素,抛出异常
throw new NoSuchElementException();
return unlinkFirst(f);
}

/*断开第一个非空节点的链接*/

private E unlinkFirst(Node<E> f) {

//获取第一个Node的item
final E element = f.item;

//获取第一个Node的Next
final Node<E> next = f.next;

//将item置为null
f.item = null;

//将next置为null,因为first是没有prev的,所以将

//Node的ele元素和next全部置为null则代表可以

//进行垃圾回收
f.next = null; // help GC

//第一个Node被移除后它next的理应的是first
first = next;

//如果被移除的Node的next现在是first是null则表示

//当前集合没有元素则last也应当是null
if (next == null)
last = null;

//如果first被移除后集合内还有元素,则新的first的prev是null
else
next.prev = null;

//计数器操作

size--;
modCount++;

//返回被移除的元素
return element;
}

removeLast删除并重新赋值Last

/*删除并返回列表中的最后一个元素。*/

public E removeLast() {

//获取最后一个Node
final Node<E> l = last;

//如果是null抛异常
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}

/*解除最后一个非空节点l的链接。*/

private E unlinkLast(Node<E> l) {

//拿到last的元素
final E element = l.item;

//拿到last的上一个
final Node<E> prev = l.prev;

//断掉指针
l.item = null;

//断掉指针,等待被回收
l.prev = null; // help GC

//last被删除后它的prev理应的是新的last
last = prev;

//如果新的last是null,则表示集合内没有元素

//first置为null
if (prev == null)
first = null;
else

//顺利成为last后它失去next的指针,也就是oldNext的指针
prev.next = null;

//计数器
size--;
modCount++;

//返回被删除的元素
return element;
}

remove(index)四种删除情况!

/*

移除此列表中指定位置的元素。将后面的元素向左移动

(从它们的索引中减去1)。返回从列表中删除的元素。

*/

public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}

/*Unlinks non-null node x.*/

E unlink(Node<E> x) {
// assert x != null;

//需要被删除Node的元素内容
final E element = x.item;

//需要被删除Node的下一个
final Node<E> next = x.next;

//需要被删除Node的上一个
final Node<E> prev = x.prev;

//如果上一个等于null表示被删除的元素是第一个

if (prev == null) {

//则需要将被删除的Node的next赋值到first
first = next;
} else {

//如果被删除的Node不是第一个,需要将它的next

prev.next = next;

//赋值给它的prev的next。并且将它的上一个指针断掉。
x.prev = null;
}

//如果被删除的Node的next是null表示它是最后一个

if (next == null) {

//则需要将它的prev赋值到last
last = prev;
} else {

//否则表示它不是最后一个,需要将被删除的Node的prev

//转移到下一个Node的prev
next.prev = prev;

//将next指针断掉
x.next = null;
}

//将元素内容指针断掉

x.item = null;

//计数器操作
size--;
modCount++;
return element;
}

remove(obj)删除指定元素的两种情况

/*如果指定元素出现,则从列表中删除第一个出现的元素。如果此列表不包含该元素,则将对其进行更改。*/

//其实这个注释是非常不令人理解的。。。我的理解是不包含该元素则不对其进行更改

public boolean remove(Object o) {

//如果被删除的是null
if (o == null) {

//从头遍历集合,根据每一个Node的item判断是不是null

//循环结束条件是next==null

for (Node<E> x = first; x != null; x = x.next) {

//如果找到了就删除还是执行的unlink()最后返回true
if (x.item == null) {
unlink(x);
return true;
}
}
} else {

//如果不是null照样也是从头遍历集合调用被删除元素的equals

//这意味着如果你被删除的元素和集合内其他元素的类型不同则

//可能会报错
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {

//如果相同则删除并且返回true
unlink(x);
return true;
}
}
}

//最后没有满足条件的返回false删除失败
return false;
}

原文地址:https://www.cnblogs.com/zumengjie/p/13607537.html