循環鏈表將尾節點指向頭節點,形成環狀結構,適用於輪詢調度、緩衝區管理等場景。本文提供生產級完整實現,涵蓋單向/雙向循環鏈表的增刪改查、邊界處理、單元測試,代碼可直接落地項目。
head 不存業務數據,head.next == head 表示空表,統一邊界邏輯ICommOperate<T> 定義增刪改查契約,便於多態替換public class SNode {
private String data;
private SNode nextNode;
// 構造器、getter/setter 省略
}
public boolean insertNode(SNode node) {
initIfEmpty(); // 空表初始化 head.next = head
if (size == 0) {
head.setNextNode(node);
node.setNextNode(head);
} else {
SNode cur = head;
while (cur.getNextNode() != head) cur = cur.getNextNode(); // 找尾
cur.setNextNode(node);
node.setNextNode(head); // 閉環
}
size++; return true;
}
遍歷找到 pos-1 節點(前驅),新節點 next 指向當前節點,前驅 next 指向新節點。位置越界自動尾插。
找到 pos-1 節點(前驅)與 pos 節點(目標)及 pos+1 節點(後繼)
前驅 next 直接指向後繼 → 目標斷鏈 → System.gc() 提示回收 → size--
public void printLink() {
if (size == 0) { println("空表"); return; }
SNode cur = head.getNextNode();
int i = 0;
while (cur != head) { // 遇頭節點停止
println("第 " + (++i) + " 個: " + cur);
cur = cur.getNextNode();
}
}
public class DNode {
private String data;
private DNode priorNode, nextNode;
// 雙向指針
}
head.next = head; head.prior = head;prior=尾節點, next=head;尾節點 next=新節點;head.prior=新節點pre.next=new; new.prior=pre; new.next=cur; cur.prior=newpre.next=cur.next; cur.next.prior=pre(尾節點特判 head.prior=pre)public static void main(String[] args) {
// 單向測試
SingleCycleLinkList scll = new SingleCycleLinkList();
Stream.of("節點1","節點2","節點3","節點4","節點5")
.map(SNode::new).forEach(scll::insertNode);
scll.printLink();
scll.insertPosNode(3, new SNode("插入指定位置"));
scll.printLink();
scll.deleteNode(3);
scll.printLink();
scll.updateNode(3, Map.of("data","modified"));
scll.printLink();
// 雙向測試
DoubleCycleLinkList dcll = new DoubleCycleLinkList();
Stream.of("節點1","節點2","節點3","節點4","節點5")
.map(DNode::new).forEach(dcll::insertNode);
dcll.printLink();
// ... 同樣驗證增刪改查
}
| 操作 | 單向循環 | 雙向循環 | ArrayList |
|---|---|---|---|
| 尾插 | O(n) | O(1)* | O(1) 摊銷 |
| 頭插 | O(1) | O(1) | O(n) |
| 中間插/刪 | O(n) 查找 + O(1) | O(n) 查找 + O(1) | O(n) 移動 |
| 正向遍歷 | O(n) | O(n) | O(n) 緩存友好 |
| 反向遍歷 | 不可 | O(n) | O(n) |
| 空間開銷 | 1 指針/節點 | 2 指針/節點 | 連續記憶體 |
* 維護 tail 指針或利用 head.prior 可 O(1) 尾插
java.util.LinkedList(雙向非循環)或 ArrayDeque,經過 JIT 優化、線程不安全但性能極佳Collections.synchronizedList 或並發包Serializable、單元測試覆蓋邊界條件