類的屬性 構造函數 LinkedList()型構造函數 LinkedList(Collection)型構造函數 核心函數分析 add(E e)函數 linklast(E e)函數分析 addLast函數的實際調用 linkFirst(E e)函數 addFirst函數的實際調用 add(int in ...
類的屬性
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
// 實際元素個數
transient int size = 0;
// 指向頭節點的指針
transient Node<E> first;
// 指向尾節點的指針
transient Node<E> last;
}
構造函數
LinkedList()型構造函數
public LinkedList() {
}
LinkedList(Collection<? extends E>)型構造函數
public LinkedList(Collection<? extends E> c) {
// 調用無參構造函數
this();
// 添加集合中所有的元素
addAll(c);
}
核心函數分析
add(E e)函數
public boolean add(E e) {
// 添加到末尾
linkLast(e);
return true;
}
linklast(E e)函數分析 addLast函數的實際調用
void linkLast(E e) {
// 記住尾結點指針
final Node<E> l = last;
// 新結點的prev為l,後繼為null,值為e
final Node<E> newNode = new Node<>(l, e, null);
// 更新尾結點指針
last = newNode;
if (l == null) // 如果鏈表為空
first = newNode; // 頭指針等於尾指針
else // 尾結點不為空
l.next = newNode; // 尾結點的後繼為新生成的結點
// 大小加1
size++;
// 結構性修改加1
modCount++;
}
linkFirst(E e)函數 addFirst函數的實際調用
private void linkFirst(E e) {
//記住頭結點
final Node<E> f = first;
//實例化新節點,prev = null,last = first
final Node<E> newNode = new Node<>(null, e, f);
//頭指針指向新節點
first = newNode;
if (f == null)
//如果頭指針為空的話,尾指針也指向新節點
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
add(int index,E element)函數
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
linkBefore(E e,Node
void linkBefore(E e, Node<E> succ) {
// 記住前驅
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++;
modCount++;
}
addAll(int index, Collection<? extends E> c)函數
// 添加一個集合
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) { // 如果插入位置為鏈表末尾,則後繼為null,前驅為尾結點
succ = null;
pred = last;
} else { // 插入位置為其他某個位置
succ = ode(index); n// 尋找到該結點
pred = succ.prev; // 保存該結點的前驅
}
for (Object o : a) { // 遍曆數組
E e = (E) o; // 向下轉型
// 生成新結點
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null) // 表示在第一個元素之前插入(索引為0的結點)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) { // 表示在最後一個元素之後插入
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
// 修改實際元素個數
size += numNew;
// 結構性修改加1
modCount++;
return true;
}
node(int index)函數
Node<E> node(int 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結點依賴於first和last指針,即使分成再多的段,定位多麼的精確,還是要從first或者last開始遍歷
remove(Object o)函數
public boolean remove(Object o) {
if (o == null) {
//同樣說明LinkedList允許插入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;
}
unlink(Node
E unlink(Node<E> x) {
//返回x的結點值
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;
}
//如果刪除的結點是尾結點,尾指針指向prev
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
//集合內容清null
x.item = null;
size--;
modCount++;
return element;
}
unlinkFirst(Node
private E unlinkFirst(Node<E> f) {
// 記住結點值和後繼
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
//頭指針指向後繼
first = next;
if (next == null)
//如果刪除結點後鏈表為空,尾指針指向空
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
unlinkLast(Node
private E unlinkLast(Node<E> l) {
// 記住結點值和前驅
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;
}