说明
本文是基于JDK7对LinkedList进行总结。通过阅读源码,对LinkedList的实现原理,特点等进行理解和掌握。
正文
LinkedList的特点
与ArrayList不同的是,LinkedList是基于双向链表实现的,适合增删多查找少的场景;相同的是都允许有空值(null),允许有重复值,插入数据是有序的,都是非线程安全的。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
LinkedList继承了AbstractSequentialList类,实现了List, Deque, Cloneable, java.io.Serializable接口。
除了可以当作链表操作外,还可以当作栈、队列或双端队列使用。
节点类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的成员变量
transient int size = 0;//链表中节点的个数
transient Node<E> first;//首节点
transient Node<E> last;//尾节点
LinkedList的构造函数
缺省构造函数
public LinkedList() { }//方法为空
指定一个Collection对象作为参数的构造函数,元素的顺序有这个对象迭代器返回的顺序决定
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
链表中的插入
LinkedList的linkFirst(E e)方法
在链头插入一个元素
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)//如果首节点为空
last = newNode;//将新节点作为尾节点
else
f.prev = newNode;//不为空 只修改第一个节点的前驱就可以
size++;//节点个数加1
modCount++;//修改次数加1
}
LinkedList的linkLast(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++;
}
LinkedList的linkBefore(E e, Node 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);
succ.prev = newNode;//将节点的前驱改为新节点
if (pred == null)//若原来前驱为空
first = newNode;//新节点作为首节点
else
pred.next = newNode;//不为空 原来前驱节点的后继节点改为新节点
size++;//节点个数加1
modCount++;
}
LinkedList的add方法
//在链头添加一个元素
public void addFirst(E e) {
linkFirst(e);
//在链尾添加一个元素
public void addLast(E e) {
linkLast(e);
}
//一般这个方法最常用
public boolean add(E e) { //此方法会返回一个boolean类型的值
linkLast(e);//是在链尾进行添加
return true;
}
//添加一个集合中的所有元素
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);//调用addAll(int index, Collection<? extends E> c)方法,
//index等于size,也就是说在链尾进行添加
}
//在某个节点前添加一个集合中的所有元素
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);//首先判断是否越界
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);//将节点作为新节点的后继
pred = succ.prev;//找出节点的前驱
}
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 {
pred.next = succ;//新节点的后继节点就是该节点
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
//在某个位置添加一个元素
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)//index==size 在链尾进行添加
linkLast(element);
else
linkBefore(element, node(index));//在index前插入元素
}
LinkedList的get方法
//得到链头元素
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
//得到链尾元素
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
//得到某个位置的元素
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
链表中的删除
在看remove方法前先看unlink方法
LinkedList的unlink方法
//删除链头元素
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;
f.next = null; // help GC 在这可以看到 删除一个节点 将该节所有属性置为null 让垃圾回收器回收
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;//节点个数减1
modCount++;
return element;//返回节点的值
}
//删除链尾元素
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;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
//在链表中删除某个指定的节点
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;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {//若后继节点为空 则将前驱节点置为尾节点
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;//将值置为null
size--;//个数减1
modCount++;
return element;//返回值
}
LinkedList的remove方法
remove方法中都是调用unlink方法
//删除并返回链头元素
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
//删除并返回链尾元素
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
//删除某个指定的元素
public boolean remove(Object o) {//此方法不返回元素的值 只返回boolean类型的值
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;
}
//删除并返回指定位置的元素
public E remove(int index) {
checkElementIndex(index);//要检查指定位置是否越界
return unlink(node(index));
}
LinkedList的clear()方法
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
//清除节点之间的链接是“不必要的”,
//但是为了确保在有可到达的迭代器时也可以释放内存,有助于GC
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;//将所有节点置为null
size = 0;//个数置为0
modCount++;
}
LinkedList的indexOf(Object o)方法
该方法返回指定元素在链表中第一次出现的位置,没有该元素则返回-1
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
LinkedList作为队列时的操作方法
peek()方法
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;//返回链头元素的值
}
element()方法
public E element() {
return getFirst();//返回链头元素的值
}
poll()方法
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);//调用unlinkFirst方法,删除并返回链头元素的值
}
remove()方法
public E remove() {
return removeFirst();//删除并返回链头元素的值
}
offer()方法
public boolean offer(E e) {
return add(e);//在链尾插入元素
}
push(E e)方法
public void push(E e) {
addFirst(e);//在链头插入元素
}
pop()方法
public E pop() {
return removeFirst();//删除并返回链头元素
}
LinkedList的toArray()方法
该方法将LinkedList中的元素转换成一个数组 该数组类型为Object
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
LinkedList的toArray(T[] a)方法
该方法将LinkedList中的元素全部放到一个数组中并返回数组,该数组的类型为参数的指定类型
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
//如果数组的长度小于元素的个数,就使用反射实例化一个长度为size的新数组
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)//若数组长度大于元素个数,将数组size位置置为null
a[size] = null;
return a;
}