Node
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;
}
}
add方法
源码
- 保存之前的尾节点
- 创建新的节点,新节点的前置直接点是之前的尾节点,后置节点为null
- 将last指向最新的尾节点
- 如果之前的链表中一个元素也没有,那么新创建的节点既是尾节点又是头结点
- 如果之前链表中已经有元素,那么将之前的尾节点指向新的节点
- 将数量加一
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* Links e as last element.
*/
void linkLast(E e) {
final Node<E> l = last;
// 创建节点,指向前一个元素,后置节点为null,本身自己作为最后一个元素
final Node<E> newNode = new Node<>(l, e, null);
// 将last指向最新的尾节点
last = newNode;
if (l == null) // e加入之前,链表中一个元素也没有
first = newNode;
else // 将之前的尾节点的next指向新的尾节点
l.next = newNode;
// 数量加1
size++;
modCount++;
}
用图像来表示加入的过程
add(int index, E element)
源码
- 查找链表中下标为index 的节点,利用二分法查找,先判断index是在左边还是右边,如果是左边,就从做往右查找,如果是右边,就从右往左查找,假设找到的节点为A。
- 如果是在尾部插入,就调用linkLast方法,其实现和add(E e)方法一样
- 如果是在中间插入,就创建新的节点,假设新的节点为B,B的后置节点为A,前置节点为A的前置节点,若A的前置节点为null(在链表头插入),就将first指向新的节点B,若A的前置节点C不为null,那么就将前置节点C的next指向新节点B。
- 将数量加1
// 父类中的方法
public void add(int index, E element) {
try {
listIterator(index).add(element);
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
}
// 返回下标为index的元素
Node<E> node(int index) {
// assert isElementIndex(index);
// 如果index在正中间的左边,那么就从做开始遍历
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
// 如果index靠右,就从右向左遍历
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
// ListItr 中的方法
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null) // 在尾部插入
linkLast(e);
else // 在中间插入
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
// 和add(E e)的实现是相同的
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++;
}
/**
* Inserts element e before non-null Node succ.
*/
void linkBefore(E e, Node<E> succ) { // succ为之前下标为index的节点
// assert succ != null;
// succ节点的前置节点
final Node<E> pred = succ.prev;
// 创建新的节点,前直接点为pred,后置节点为succ
final Node<E> newNode = new Node<>(pred, e, succ);
// 将succ的前置节点指向新的节点
succ.prev = newNode;
if (pred == null)// 如果实在头部插入,那么新的节点就是头结点
first = newNode;
else// 将pred的next指向新的节点
pred.next = newNode;
// 将数量加1
size++;
modCount++;
}
添加节点的流程图
删除元素
remove()
调用这个方法,删除的是头结点。
/**
* Retrieves and removes the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E remove() {
return removeFirst();
}
/**
* Removes and returns the first element from this list.
*
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeFirst() {
final Node<E> f = first;
// 链表中没有元素,删除元素,会抛出异常
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* Unlinks non-null first node f.
*/
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
// 头结点的后置节点
final Node<E> next = f.next;
// 将item置为null,帮助GC垃圾回收
f.item = null;
f.next = null; // help GC
// 之前链表的第二个节点就成为了头节点
first = next;
// 如果删除了节点之后,链表中没有节点了,尾节点需要置为null
if (next == null)
last = null;
else // 将当前头结点的前置节点置为null
next.prev = null;
// 数量减一
size--;
modCount++;
return element;
}