
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.内部类```javaprivate 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; // 将尾结点赋给lfinal Node<E> newNode = new Node<>(l, e, null); // 给newNode赋值,前驱指针指向l,后继指针指向nulllast = newNode; // 移动尾指针// 完善指针指向if (l == null)first = newNode; // 如果尾指针是空的,该节点是第一个节点,赋头指针elsel.next = newNode; // 否则,连接l的next指针size++; // 增加个数modCount++;}
- addFirst与offerFirst```javapublic void addFirst(E e) {linkFirst(e);}private void linkFirst(E e) {// final修饰,不允许修改// 将头结点赋给ffinal Node<E> f = first;// 定义插入节点,前驱指针指向null,后继指针指向ffinal Node<E> newNode = new Node<>(null, e, f);// 移动头指针first = newNode;// 完善指针指向if (f == null)last = newNode; // 如果尾指针是空的,该节点是第一个节点,对尾指针赋值elsef.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.2linkBefore(element, node(index));
}
// succ节点是原来在index位置的节点void linkBefore(E e, Node<E> succ) {// assert succ != null;// 将succ节点的前驱结点指向predfinal Node<E> pred = succ.prev;// 定义新节点,前驱结点指向pred,后继节点指向succfinal 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)方法。```javapublic 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;elsepred.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的后继结点赋给nextfinal Node<E> next = x.next;// x的前驱结点赋给prevfinal Node<E> prev = x.prev;// 如果prev是null,说明该节点是第一个节点if (prev == null) {// 头结点后移first = next;} else {// 否则不是头结点,修改prev的next指针指向next节点prev.next = next;// x的prev指针置nullx.prev = null;}// 如果要删除的节点是尾结点if (next == null) {// 尾结点前移last = prev;} else {// 否则不是尾结点,修改next的prev指针指向prev节点next.prev = prev;// x的next指针置为nullx.next = null;}// 清空x的值x.item = null;//个数-1size--;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方法```javapublic 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 GCfirst = next;// 如果next是null,说明链表就一个头结点被删了if (next == null)// 尾结点置空last = null;else// 断next的头指针,next就是新头节点next.prev = null;// 个数减1size--;modCount++;// 返回删除的节点值return element;}
removeLast方法
public E removeLast() {final Node<E> l = last;if (l == null)throw new NoSuchElementException();return unlinkLast(l);}// 知道自己是尾结点,删除尾结点lprivate 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 GClast = prev;// 如果prev为空,就一个尾节点被删了,if (prev == null)// 头结点置nullfirst = null;else// 否则断prev的next指针,prev就是新的尾结点prev.next = null;size--;modCount++;// 返回删除的节点值return element;}
removeLastOccurrence(o)方法
public boolean removeLastOccurrence(Object o) {// 从后往前遍历,调用unlink方法删除o,如果不存在,返回falseif (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;}
