简介
一个非同步的双链表集合,双链表的数据结构示意图如下:
在LinkedList内部包含一个Node的内部类 ,这个内部类是每一个元素的信息。
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
}
从Node的代码中可以非常清楚的看到,每个元素中包含每个元素、以及上一个元素、下一个元素的指针。
重要方法分析
link
link 相关方法包括linkFirst、linkLast、linkBefore,主要是为了插入一个element,并且和当前链表完成双向绑定。在这里可以和arrayList进行对比,这里可以动态的插入元素,并且不需要进行扩容操作。下面以linkLast为例进行分析
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++;
modCount++;
}
1.LinkedList的last赋予临时变量l;
2.linkLast方法中会创建新的Node实例,LinkedList的last会赋予当前Node的prev,赋值prev完成了双指针链表的单向链接。
3.LinkedList的last会指向给newNode既新创建的Node实例。
4.判断临时变量f,其实也是newNode的prev是否为空,如果为空newNode,说明LinkeList集合现在是一个空集合,这时把newNode也赋值给LinkedList的first。
5.如果临时变量l不为空,说明集合已经不为空,把newNode赋值给l.next,完成双指针链表的双向绑定。
node
Node<E> node(int 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;
}
}
获取指定下标的节点数据,这里和arrayList的查询形成鲜明的对比,arrayList只需要查询数组的下标即可,但是在这里必须要遍历节点。虽然根据size/2进行优化,但是随着N的增加,时间复杂度也必然增加。
unlink
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;
}
1.移除prev引用
如果Node的prev为空,说明当前节点为头部节点,那么把Node的next指向LinkedList的first。
如果Node的prev不为空,那么把prev.next指向Node.next,并且把Node.next置为空。
2.移除next引用
如果Node的next为空,说明当前节点是最后一个节点,那么把Node的prev指向LinkedList的last。
如果Node的next不为空,那么把next.prev指向Node.prev,并且把Node.prev置为空。
3.在步骤1、2中完成了双指针的摘链,剩下完成node置空、size--等业务操作。