Java LinkedList 實作了 List、Deque、Queue 多重介面,功能豐富但過於暴露內部細節。透過封裝模式,僅暴露堆疊 (LIFO) 或佇列 (FIFO) 所需的最小介面集合,既能確保語義正確性,又能隱藏實作細節,提升代碼安全性與可維護性。
import java.util.LinkedList;
public class Stack<T> {
private LinkedList<T> storage = new LinkedList<T>();
/** 入堆疊 (推入堆疊頂端) */
public void push(T v) {
storage.addFirst(v);
}
/** 查看堆疊頂端元素 (不移除) */
public T peek() {
return storage.getFirst();
}
/** 出堆疊 (移除並回傳頂端元素) */
public T pop() {
return storage.removeFirst();
}
/** 判斷堆疊是否為空 */
public boolean empty() {
return storage.isEmpty();
}
/** 列印堆疊內容 (除錯用) */
@Override
public String toString() {
return storage.toString();
}
}
push/pop/peek/empty 四大核心操作,符合堆疊 LIFO 語義addFirst/removeFirst/getFirst 皆為 O(1) 常數時間LinkedList 實作,零額外負擔import java.util.LinkedList;
import java.util.Queue;
public class MyQueue<T> {
private Queue<T> storage = new LinkedList<T>();
/** 插入元素至佇列尾部 */
public void offer(T v) {
storage.offer(v);
}
/** 檢索但不移除佇列頭部,空佇列回傳 null */
public T peek() {
return storage.peek();
}
/** 檢索但不移除佇列頭部,空佇列拋出異常 */
public T element() {
return storage.element();
}
/** 檢索並移除佇列頭部,空佇列回傳 null */
public T poll() {
return storage.poll();
}
/** 檢索並移除佇列頭部,空佇列拋出異常 */
public T remove() {
return storage.remove();
}
/** 判斷佇列是否為空 */
public boolean empty() {
return storage.isEmpty();
}
/** 列印佇列內容 (除錯用) */
@Override
public String toString() {
return storage.toString();
}
}
offer/peek/element/poll/remove 五大核心方法,涵蓋「失敗回傳 null」與「失敗拋出異常」兩種語義Queue<T> 而非 LinkedList<T>,降低耦合度,未來可替換為 ArrayDeque、PriorityQueue 等實作| 類別 | 問題 | 建議替代方案 |
|---|---|---|
java.util.Stack | 繼承自 Vector (同步、效能差)、暴露 get(index) 破壞 LIFO、方法命名不一致 (push/pop vs add/remove) | 自行封裝 Deque (如 ArrayDeque) 或本文 Stack<T> |
java.util.Queue (介面) | 僅為介面,需自行選擇實作類別 | 本文 MyQueue<T> 封裝 LinkedList,或直接使用 ArrayDeque |
public boolean isValidParentheses(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
} else if (c == ')' || c == ']' || c == '}') {
if (stack.empty()) return false;
char top = stack.pop();
if ((c == ')' && top != '(') ||
(c == ']' && top != '[') ||
(c == '}' && top != '{')) {
return false;
}
}
}
return stack.empty();
}
public void bfs(TreeNode root) {
MyQueue<TreeNode> queue = new MyQueue<>();
queue.offer(root);
while (!queue.empty()) {
TreeNode node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
maxSize 參數,滿載時 push/offer 拋出異常或阻塞Collections.synchronizedList 或改用 ConcurrentLinkedQueue/ArrayBlockingQueueIterable<T> 介面,支援 for-each 遍歷 (堆疊從頂到底、佇列從頭到尾)Serializable,確保內部 LinkedList 可序列化本文展示基於 LinkedList 封裝堆疊與佇列的最佳實踐:
addFirst/removeFirst/getFirst 實現 O(1) LIFOQueue 介面實現 O(1) FIFO,支援雙重語義 (null/異常)Vector、Stack 等類別這種封裝設計不僅提升代碼可讀性與安全性,更為未來效能優化 (如改用 ArrayDeque) 預留彈性空間。