push),元素按到達順序疊放,最新在頂。pop),元素順序與佇列 FIFO 一致,最舊在頂。outStack 為空,將 inStack 全部 pop 再 push 進 outStack,順序自動反轉。
import java.util.Stack;
public class QueueWithTwoStacks {
private final Stack inStack = new Stack<>();
private final Stack outStack = new Stack<>();
/** 入隊:O(1) */
public void appendTail(E e) {
inStack.push(e);
}
/** 出隊:均攤 O(1) */
public E deleteHead() {
if (outStack.isEmpty()) {
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
if (outStack.isEmpty()) {
throw new NoSuchElementException("Queue is empty");
}
return outStack.pop();
}
/** 輔助:查看隊首不移除 */
public E peek() {
if (outStack.isEmpty()) {
while (!inStack.isEmpty()) outStack.push(inStack.pop());
}
return outStack.peek();
}
public boolean isEmpty() { return inStack.isEmpty() && outStack.isEmpty(); }
public int size() { return inStack.size() + outStack.size(); }
}
inStack.push → inStack.pop → outStack.push → outStack.pop。deleteHead() 觸發搬移 O(k),但後續 k-1 次為 O(1)。O(N) — 兩棧共存元素總數等於佇列大小,無額外開銷。
| 需求 | 修改點 |
|---|---|
| 線程安全 | 用 ArrayDeque + synchronized 或 ConcurrentLinkedQueue 直接替代 |
| 雙端佇列 | 需四棧或改用 LinkedList |
| 優先級佇列 | 棧無序,不適用,改用 PriorityQueue |
| 固定容量 | 入隊前檢查 size() == capacity 拋異常或阻塞 |
push 後旋轉 n-1 次,pop 直接 poll。getMin() O(1) 的棧:輔助棧同步存最小值。remove(0) 觸發陣列位移 O(n);環形陣列可 O(1) 但需擴容策略。**直接用 ArrayDeque** — 實現雙端佇列、陣列基底、無容量上限、非線程安全但效能極佳,JDK 內部 Stack 文檔已建議棄用。
雙棧佇列是經典面試題,理解「空間換時間、延遲反轉、均攤分析」三大思想,比背誦代碼更有價值。