LinkedList定义了三个成员变量:
int size
Node<E> first
Node<E> last
Node是一个已经定义的内部类:
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;
}
}
可以用这张图来表示节点的结构
首先看一下LinkedList的构造方法:
LinkedList提供了两类构造方法:
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
第一种为默认的无参构造方法。
第二种构造方法传入的参数为实现了Collection接口的任意集合类型。
LinkedList 的方法
关键的几个内部方法(头部添加删除,尾部添加删除,获取指定节点,指定节点的添加删除)分析
在头部添加:linkFirst(E e):
private void linkFirst(E e) {
final Node<E> f = first; //保存当前链表的头节点
final Node<E> newNode = new Node<>(null, e, f);//新建节点,节点的next指向头节点
first = newNode; //链表的头节点更新为新建的节点
if (f == null) //对链表进行判断,如果链表为空,则新插入的节点作为头节点
last = newNode;//如果之前的链表为空,则尾节点更新为新建的节点
else
f.prev = newNode;//则之前的头节点的pre指向新建的节点
size++;
modCount++;
}
删除头节点:unlinkFirst(Node f):
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item; //保存头节点的值
final Node<E> next = f.next;//保存头节点的下一个节点的信息
f.item = null; //将节点的值和next置为null
f.next = null; // help GC
first = next; //头节点更新为下一个节点
if (next == null) //如果当前的头节点是链表中的唯一的节点
last = null; //尾节点置为null
else
next.prev = null;//下一个节点的pre设为
size--;
modCount++;
return element;
}
在尾部添加:LinkLast(E e)
void linkLast(E e) {
final Node<E> l = last; //保存当前的尾节点信息
final Node<E> newNode = new Node<>(l, e, null);//新建一个节点,节点的pre为之前的尾节点,next为null
last = newNode; //尾节点更新为新建的节点
if (l == null) //如果链表为空
first = newNode;//头节点也更新为新建的节点
else
l.next = newNode;//修改之前的尾节点的next值为新建的节点
size++;
modCount++;
}
删除尾部节点:unlinklast(E e)
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item; //保存尾节点值
final Node<E> prev = l.prev;//保存尾节点之前的节点的信息
l.item = null;//将为节点的值和pre更改为null
l.prev = null; // help GC
last = prev;//更新尾节点为前一个节点
if (prev == null)//如果当前节点为链表中的唯一节点
first = null;//头节点为null
else
prev.next = null;
size--;
modCount++;
return element;
}
指定节点前的添加
void linkBefore(E e, Node<E> succ)
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev; //获取指定节点的前一个节点
final Node<E> newNode = new Node<>(pred, e, succ);//新建节点,节点的pre为指定节点的前一个节点,next为指定节点
succ.prev = newNode; //修改指定节点的pre为新建节点
if (pred == null) //如果指定节点为头节点
first = newNode; //first指向新建的节点
else
pred.next = newNode; //指定节点的前一个节点的next为新建节点
size++;
modCount++;
}
删除指定节点
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; //first指向删除节点的后一个节点
} else {
prev.next = next; //删除节点的前一个节点的next指向删除节点的后一个节点
x.prev = null;
}
if (next == null) { //如果删除的是尾节点
last = prev; //last指向删除节点的前一个节点
} else {
next.prev = prev;//删除节点的后一个节点pre指向删除节点的前一个节点
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
获取指定节点
Node<E> node(int index) {
// assert isElementIndex(index);
//对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;
}
}
LinkedList 特点
- 双向链表实现
- 元素时有序的,输出顺序与输入顺序一致
- 允许元素为 null
- 所有指定位置的操作都是从头开始遍历进行的
- 和 ArrayList 一样,不是同步容器