LinkedList 是基於雙向鏈表實現的 List 與 Deque 雙重身份集合:
List → 支持索引訪問(但效率低)Deque → 天然支持棧(LIFO)、隊列(FIFO)、雙端隊列操作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;
}
}
transient Node<E> first; // 頭節點
transient Node<E> last; // 尾節點
transient int size; // 元素數量
無容量限制,動態擴容;節點包含前驅/後繼指針,插入刪除 O(1),隨機訪問 O(n)。
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;
}
}
獲取、設置、插入、刪除指定索引元素均調用此方法,雙向遍歷將最長路徑縮短一半。
// 在 succ 節點前插入
void linkBefore(E e, Node<E> succ) {
Node<E> pred = succ.prev;
Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null) first = newNode;
else pred.next = newNode;
size++; modCount++;
}
// 解鏈節點
E unlink(Node<E> x) {
E element = x.item;
Node<E> next = x.next, 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; // help GC
size--; modCount++;
return element;
}
| 遍歷方式 | 耗時 | 推薦等級 | 備註 |
|---|---|---|---|
| for-each / Iterator | ~5 ms | ⭐⭐⭐⭐⭐ | 順序訪問,無索引開銷 |
for (int i=0; i| ~3700 ms | ⭐ | 隨機訪問,每次 O(n/2),極慢 | |
| pollFirst() / pollLast() | ~6-8 ms | ⭐⭐⭐⭐ | 邊遍歷邊刪除,慎用 |
| removeFirst() / removeLast() | ~2 ms | ⭐⭐⭐⭐ | 最快但銷毀原數據 |
鐵律:絕不使用索引循環遍歷 LinkedList;只讀場景首選 for-each 或 Iterator。
| 操作 | 拋異常 | 返回特殊值 |
|---|---|---|
| 插入頭部 | addFirst(e) | offerFirst(e) |
| 插入尾部 | addLast(e) | offerLast(e) |
| 移除頭部 | removeFirst() | pollFirst() |
| 移除尾部 | removeLast() | pollLast() |
| 查看頭部 | getFirst() | peekFirst() |
| 查看尾部 | getLast() | peekLast() |
Queue 等價:add = addLast、offer = offerLast、remove = removeFirst、poll = pollFirst、element = getFirst、peek = peekFirst。
Stack 等價:push = addFirst、pop = removeFirst、peek = peekFirst。
(文中完整代碼展示了 LinkedList 作為隊列/棧的實際業務用法,此處省略,重點關注上表等價關係。)
offer/poll,棧用 push/pop)。for-each 或 Iterator,拒絕 get(i) 循環。Collections.synchronizedList 或改用 ConcurrentLinkedDeque。