(一)LinkedList的定义
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
其中,AbstractSequentialList是AbstractList通过索引访问、删除元素的骨干实现,而Deque定义了一套能从链表头尾访问的接口,使得LinkedList能当做双端队列使用。Deque插入,删除,访问的方法,每种方法都存在两种形式:操作失败时抛出异常、返回特殊值(null或false):
第一个元素(头部) 最后一个元素(尾部)
抛出异常 特殊值 抛出异常 特殊值
插入 addFirst(e) offerFirst(e) addLast(e) offerLast(e)
移除 removeFirst() pollFirst() removeLast() pollLast()
访问 getFirst() peekFirst() getLast() peekLast()
(二)重要属性:
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
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;
}
}
其中size是链表中元素的大小,first是指向链表头结点的引用,last是指向链表尾结点的引用。Node是链表结点的定义,item是链表的元素,next是指向下一个结点的引用,prev是指向上一个结点的引用。
(二)添加元素,删除元素
LinkedList添加元素:
public boolean add(E e) {
linkLast(e);
return true;
}
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++;
}
在添加元素的过程中,先获取指向链表尾部结点的引用last,然后构造一个新结点newNode,newNode的前一个引用指向原链表的尾部,下一个引用为null。接着,将原链表尾部的引用指向新结点,判断原来的尾结点是否为空,为空则将原链表的头引用指向新结点,不为空则将原链表的尾结点的下一个引用指向新结点,元素结点数量+1,结构性修改计数+1。至此,新元素被添加到链表的末尾。
(三)访问元素
LinkedList访问元素:
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
检查索引是否越界:
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
根据索引获取结点:
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;
}
}
可以看到,首先判断当前索引index是否小于链表中元素大小的一半:index < (size >> 1),小于则从链表头部开始遍历,否则,从链表尾部开始遍历,直至找到目标。也因为此,当LinkedList中元素数量很多时,通过索引访问LinkedList将变得很慢,时间复杂度为O(n)。
(四)LinkedList实现队列,栈
当用LinkedList实现队列时,等效方法分别如下:
实现队列:
队列方法 等效方法
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()
/**
* @Author: weiwenfeng
* @Date: 2018/11/16
*/
public class Queue<E> {
private LinkedList<E> linkedList = new LinkedList<E>();
boolean add(E e){
linkedList.addLast(e);
return true;
}
boolean offer(E e){
linkedList.offerLast(e);
return true;
}
E remove(){
return linkedList.removeFirst();
}
E poll(){
return linkedList.pollFirst();
}
E element(){
return linkedList.getFirst();
}
E peek(){
return linkedList.peekFirst();
}
}
实现栈:
栈方法 等效方法
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()
/**
* @Author: weiwenfeng
* @Date: 2018/11/16
*/
public class Stack<E> {
private LinkedList<E> linkedList = new LinkedList<>();
E push(E e){
linkedList.addFirst(e);
return e;
}
E pop(){
return linkedList.removeFirst();
}
E peek(){
return linkedList.peekFirst();
}
}