public class LinkedList2.2 Nodeextends AbstractSequentialList implements List , Deque , Cloneable, java.io.Serializable { // 该集合中元素的个数 transient int size = 0; // 指向链表的第一个节点 transient Node first; // 指向链表的最后一个节点 transient Node last; public LinkedList() { } }
1、在ArrayList中,底层数据结构是数组,LinkedList的底层数据结构是双向链表,双向链表由一个一个的Node构成,添加到LinkedList中的元素保存在Node中;
2、Node是LinkedList的一个内部类
private static class Node2.3 增加元素{ E item; Node next; Node prev; Node(Node prev, E element, Node next) { this.item = element; this.next = next; this.prev = prev; } }
LinkedList的无参构造方法只是简单创建了一个LinkedList,并没有做其他的操作,看一下add方法
// 调用LinkedList的add方法,最终完成保存操作调用的方法是linkLast(E e)
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
// 定义一个临时变量,指向链表的最后一个节点
final Node l = last;
// 创建一个新的节点
final Node 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));
}
// 在此方法中,优化了遍历节点的数量 // 先看一下要插入的位置离链表的头部近,还是离链表的尾部近 Nodenode(int index) { if (index < (size >> 1)) { // 离头部近,修改要插入位置之前节点的next Node x = first; for (int i = 0; i < index; i++) x = x.next; // 返回要插入位置的节点 return x; } else { // 离尾部近,修改要插入位置之后节点的prev Node x = last; for (int i = size - 1; i > index; i--) x = x.prev; // 返回要插入位置的节点 return x; } }
void linkBefore(E e, Nodesucc) { // 获取要插入位置的节点的前一个节点 final Node pred = succ.prev; // 根据传入的元素,创建一个新的节点 final Node 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属性。



