2 LinkedList
2.1 无参构造方法
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
// 该集合中元素的个数
transient int size = 0;
// 指向链表的第一个节点
transient Node<E> first;
// 指向链表的最后一个节点
transient Node<E> last;
public LinkedList() {
}
}
2.2 Node
1、在ArrayList中,底层数据结构是数组,LinkedList的底层数据结构是双向链表,双向链表由一个一个的Node构成,添加到LinkedList中的元素保存在Node中;
2、Node是LinkedList的一个内部类
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;
}
}
2.3 增加元素
LinkedList的无参构造方法只是简单创建了一个LinkedList,并没有做其他的操作,看一下add方法
// 调用LinkedList的add方法,最终完成保存操作调用的方法是linkLast(E e)
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
// 定义一个临时变量,指向链表的最后一个节点
final Node<E> l = last;
// 创建一个新的节点
final Node<E> newNode = new Node<>(l, e, null);
// 把新创建的节点变为最后一个节点
last = newNode;
if (l == null)
// 如果当前链表的最后一个节点为null,说明当前链表是空的
// 把新创建的节点当作链表的首个节点
first = newNode;
else
// 把新创建的节点放到链表末尾
l.next = newNode;
// 更新集合元素的数量以及操作次数
size++;
modCount++;
}
2.4 向指定位置添加元素
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
// 当指定的位置等于当前集合中元素的个数,直接添加到链表末尾
linkLast(element);
else
linkBefore(element, node(index));
}
// 在此方法中,优化了遍历节点的数量
// 先看一下要插入的位置离链表的头部近,还是离链表的尾部近
Node<E> node(int index) {
if (index < (size >> 1)) {
// 离头部近,修改要插入位置之前节点的next
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
// 返回要插入位置的节点
return x;
} else {
// 离尾部近,修改要插入位置之后节点的prev
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
// 返回要插入位置的节点
return x;
}
}
void linkBefore(E e, Node<E> succ) {
// 获取要插入位置的节点的前一个节点
final Node<E> pred = succ.prev;
// 根据传入的元素,创建一个新的节点
final Node<E> newNode = new Node<>(pred, e, succ);
// 修改新节点后一个节点的prev
succ.prev = newNode;
// 修改新节点前一个节点的next
if (pred == null)
// 如果当前链表中没有节点,把新插入的节点当作头节点
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
向指定位置插入元素总结:
(0) 在添加新节点之前会对插入的位置进行校验,如超过当前集合的size或者小于0,会抛出异常;
(1)先获取到要插入位置的节点,如向第5个位置插入新节点,会先获取到原链表中第五个位置的节点;
(2)然后根据要插入的元素创建一个新的节点;
(3)修改新节点的prev和next属性;
(4)修改新节点前一个节点的next属性;
(5)修改新节点后一个节点的prev属性。