1.概述
高效插入和刪除的有序序列
線程不安全,非同步
數據結構:鏈表(雙向鏈表)
繼承了AbstractSequentialList
,可以作爲棧和隊列使用
實現了Deque
,可以做雙向鏈表
遍歷時推薦使用iterater
關係圖:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
2.源碼
常用屬性:
// 元素個數
transient int size = 0;
// 頭節點
transient Node<E> first;
//尾節點
transient Node<E> last;
// 記錄修改次數,與線程有關的屬性(平時使用並不多)
protected transient int modCount = 0;
常用構造方法:
// 默認構造方法
public LinkedList() {}
// 指定添加元素,並不常用
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
核心內部類:
/**
* 鏈表的數據結構
*/
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的迭代有關
* 而且在迭代的過程中能對元素進行操作
*/
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
// methods()....
}
核心方法:
/**
* 添加元素到鏈表尾部
*/
public boolean add(E e) {
// 實際添加到末尾
linkLast(e);
return true;
}
/**
* Links e as last element.
*/
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++;
}
// ---------
重點看一下刪除元素的過程
/**
* Removes the first occurrence of the specified element from this list
* 移除鏈表第一個匹配的元素
*/
public boolean remove(Object o) {
// 遍歷鏈表,找到符合的結點,再使用unlink真正移除該結點
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;
}
}
}
// 沒找到則返回 false
return false;
}
/**
* Unlinks non-null node x.
*/
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;
// 移除頭結點,頭結點改變成頭結點的next
if (prev == null) {
first = next;
} else {
// 移除中間結點的一半引用(指針)操作(這個操作自己畫一張圖看起來更加直觀)
prev.next = next;
x.prev = null;
}
// 移除尾結點,尾結點改變爲尾結點的pre
if (next == null) {
last = prev;
} else {
// 移除中間結點的另一半引用(指針)操作
next.prev = prev;
x.next = null;
}
// 前面的prev和next的引用都清除了,現在清楚數據域的引用
x.item = null;
size--;
modCount++;
return element;
}
上面這些方法中,重點學習unlinck(),在指定位置插入也是相似的。
參考
Java集合源碼分析(二)Linkedlist
原文:LinkedList源碼分析
可以看一下我用Java寫的線性表的鏈式實現