public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}
继承于 AbstractSequentialList ,本质上面与继承 AbstractList 没有什么区别,AbstractSequentialList 完善了 AbstractList 中没有实现的方法。
接口
- Serializable:成员变量 Node 使用 transient 修饰,通过重写read/writeObject 方法实现序列化。
- Cloneable:重写clone()方法,通过创建新的LinkedList 对象,遍历拷贝数据进行对象拷贝。
- Deque:实现了Collection 大家庭中的队列接口,说明他拥有作为双端队列的功能。
1. 成员变量
没有MAX_ARRAY_SIZE限制,是由于链表没有长度限制的原因。 ```java // 节点个数 transient int size = 0;
// 头结点
transient Node
// 尾结点
transient Node
<a name="aXs65"></a>
## 2.内部类
```java
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;
}
}
节点有头尾指针,说明是个双向链表。LinkedList1.6版本及以前,只通过一个header头指针保存队列头和尾。之后头尾节点分开了,节点更名为Node。
2.构造方法
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
3.方法
特有的方法主要是针对头尾进行操作。注意对节点下标的记录也是从0开始的。
3.1 添加方法
继承于AbstractList的方法
- boolean add(E e)[AbstractList方法]:在尾部添加节点。底层调用了linkLast方法,有返回值true
- boolean addAll(Collection<? extends E> c)[AbstractList方法]:在尾部添加集合节点。底层调用了addAll(index, c)方法。
继承于AbstractSequentialList的方法
- void add(int index,E e)[AbstractSequentialList方法]:在指定位置添加节点。没有返回值
- boolean addAll(int index, Collection<? extends E> c)[AbstractSequentialList方法]:在指定位置添加集合节点
实现接口Deque的方法:
- void addFirst(E e)[Deque方法]:在头部添加节点。底层调用了linkFirst方法,没有返回值
- void addLast(E e)[Deque方法]:在尾部添加节点。底层调用了linkLast方法,没有返回值
- boolean offer(E e) [Deque方法]:底层调用的add(E e)方法,有返回值true。1.5
- boolean offerFirst(E e)[Deque方法]:底层调用了addFirst方法,有返回值true。 1.6
- boolean offerLast(E e)[Deque方法]:底层调用了addLast方法,有返回值true。1.6
源码:
add与addLast与offer与offerLast ```java public boolean add(E e) {
linkLast(e);
return true;
}
public void addLast(E e) {
linkLast(e);
}
public boolean offer(E e) {
return add(e);
}
public boolean offerLast(E e) {
addLast(e);
return true;
}
void linkLast(E e) {
// final修饰,不允许修改
final Node<E> l = last; // 将尾结点赋给l
final Node<E> newNode = new Node<>(l, e, null); // 给newNode赋值,前驱指针指向l,后继指针指向null
last = newNode; // 移动尾指针
// 完善指针指向
if (l == null)
first = newNode; // 如果尾指针是空的,该节点是第一个节点,赋头指针
else
l.next = newNode; // 否则,连接l的next指针
size++; // 增加个数
modCount++;
}
- addFirst与offerFirst
```java
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
// final修饰,不允许修改
// 将头结点赋给f
final Node<E> f = first;
// 定义插入节点,前驱指针指向null,后继指针指向f
final Node<E> newNode = new Node<>(null, e, f);
// 移动头指针
first = newNode;
// 完善指针指向
if (f == null)
last = newNode; // 如果尾指针是空的,该节点是第一个节点,对尾指针赋值
else
f.prev = newNode; // 连接f的pre指针
size++; // 增加个数
modCount++;
}
add(index, e): ```java public void add(int index, E element) {
// 检验index的合法性
checkPositionIndex(index);
// 如果是末尾,直接加入到末尾
if (index == size)
linkLast(element);
else
// 否则,在index处添加节点, node(index)方法找到添加的位置,参见3.2
linkBefore(element, node(index));
}
// succ节点是原来在index位置的节点
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
// 将succ节点的前驱结点指向pred
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的后继指针
pred.next = newNode;
size++;
modCount++;
}
addAll(index, c)方法:思路同add(index,succ)方法。
```java
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
//找pred指针,是否是末尾插入。
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
// 一次连接c中的节点
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
// 判断是否是第一个位置
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
// 如果是在末尾插入,定位尾指针
if (succ == null) {
last = pred;
} else {
// 否则,将c的尾节点与原队列的succ节点连接
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
3.2 get方法
继承于AbstractSequentialList的方法。
获得指定位置的节点的值
public E get(int index) {
// 检验index值是否合法
checkElementIndex(index);
return node(index).item;
}
// 返回找到的节点
Node<E> node(int index) {
// assert isElementIndex(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;
}
}
3.3 修改方法set
继承于AbstractSequentialList的方法。
修改指定位置的节点的值,返回旧值
public E set(int index, E element) {
// 检验
checkElementIndex(index);
// node方法查找该位置的节点
Node<E> x = node(index);
// 更新新值并返回旧值
E oldVal = x.item;
x.item = element;
return oldVal;
}
3.4 删除方法
继承于AbstractSequentialList的方法:
- E remove(int index):根据index删除节点,返回删除节点的值。
- boolean remove(Object o):根据值删除节点,返回true/false
实现接口Deque的方法:
- boolean remove():删除头结点。底层调用的removeFirst方法。返回true/false。1.5
- E removeFirst():删除头结点,返回删除节点的值
- E removeLast():删除尾结点,返回删除节点的值。
- boolean removeFirstOccurrence(Object o):删除第一次出现的o节点,从头开始遍历。底层调用remove()方法。返回true/false。1.6
- boolean removeLastOccurrence(Object o):删除最后一次出现的o节点,从尾开始遍历。返回true/false。1.6
remove(int index)方法
定义前后节点,分别断前后指针(判断是否是头尾节点),清空值,个数-1,modCount++,返回删除节点的值
public E remove(int index) {
checkElementIndex(index);
// node方法找到index对应的节点
return unlink(node(index));
}
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
// x的后继结点赋给next
final Node<E> next = x.next;
// x的前驱结点赋给prev
final Node<E> prev = x.prev;
// 如果prev是null,说明该节点是第一个节点
if (prev == null) {
// 头结点后移
first = next;
} else {
// 否则不是头结点,修改prev的next指针指向next节点
prev.next = next;
// x的prev指针置null
x.prev = null;
}
// 如果要删除的节点是尾结点
if (next == null) {
// 尾结点前移
last = prev;
} else {
// 否则不是尾结点,修改next的prev指针指向prev节点
next.prev = prev;
// x的next指针置为null
x.next = null;
}
// 清空x的值
x.item = null;
//个数-1
size--;
modCount++;
// 返回删除节点的值
return element;
}
- remove(Object o)与removeFirstOccurrence(o)方法
```java
public boolean remove(Object o) {
}// 遍历,调用unlink释放,如果不存在,返回false。从前往后找
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
remove与removeFirst方法
```java
public E remove() {
return removeFirst();
}
public E removeFirst() {
// 链表判空
final Node<E> f = first;
// 如果为null,抛出异常
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
// 知道自己是头结点了。f就是要删的头结点
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
// f的下一个节点为头结点
final Node<E> next = f.next;
f.item = null;
// 断f的next指针
f.next = null; // help GC
first = next;
// 如果next是null,说明链表就一个头结点被删了
if (next == null)
// 尾结点置空
last = null;
else
// 断next的头指针,next就是新头节点
next.prev = null;
// 个数减1
size--;
modCount++;
// 返回删除的节点值
return element;
}
removeLast方法
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
// 知道自己是尾结点,删除尾结点l
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
// l的上一个节点就是新的尾结点
final Node<E> prev = l.prev;
l.item = null;
// 断l的prev指针
l.prev = null; // help GC
last = prev;
// 如果prev为空,就一个尾节点被删了,
if (prev == null)
// 头结点置null
first = null;
else
// 否则断prev的next指针,prev就是新的尾结点
prev.next = null;
size--;
modCount++;
// 返回删除的节点值
return element;
}
removeLastOccurrence(o)方法
public boolean removeLastOccurrence(Object o) {
// 从后往前遍历,调用unlink方法删除o,如果不存在,返回false
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
细节
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* Tells if the argument is the index of an existing element.
* remove方法
*/
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
/**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
* add方法
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
3.5 双端链表方法
实现Deque接口的方法:
- 添加:(参见3.1)
- boolean offer(E e) 1.5
- boolean offerFirst(E e) 1.6
- boolean offerLast(E e) 1.6
- void push(E e) :在头部加入节点,底层调用的addFirst(e)方法。 1.6。
- 删除:
- E poll():检索并删除头结点,底层与pollFirst方法相同 1.5
- E pollFirst():检索并删除头结点 1.6
- E pollLast():检索并删除尾结点 1.6
- E pop():检索并删除头结点,如果为null抛出异常,底层调用removeFirst() 1.6
- 查找:
- E peek():返回头结点的值,如果为空返回null。1.5
- E peekFirst(): 返回头结点的值,如果为空返回null。1.6
- E peekLast(): 返回尾结点的值,如果为空返回null。1.6
poll
全部都是判空然后调用,如果为null返回null,不会抛出异常(remove和pop方法返回异常)。
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
pop
public E pop() {
return removeFirst();
}
push
public void push(E e) {
addFirst(e);
}
peek
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}