Java 6 引入 ArrayDeque,作為 Deque 接口的可變長數組實現,完全可以替代 老舊的 Stack (同步開銷大) 和 LinkedList (記憶體碎片化)。本文演示其作為棧/隊列的高效用法。
transient E[] elements)addFirst/addLast, removeFirst/removeLast, getFirst/getLast 均攤 O(1)Deque、Queue、Cloneable, Serializablepublic class ArrayDequeStack{ private final Deque deque = new ArrayDeque<>(); public void push(E e) { deque.addFirst(e); } public E pop() { return deque.removeFirst(); } public E peek() { return deque.peekFirst(); } public boolean isEmpty() { return deque.isEmpty(); } public int size() { return deque.size(); } } // 測試 ArrayDequeStack stack = new ArrayDequeStack<>(); for (int i = 0; i < 5; i++) stack.push(i); System.out.println(stack); // [4, 3, 2, 1, 0] System.out.println(stack.pop()); // 4 System.out.println(stack.peek()); // 3
public class ArrayDequeQueue{ private final Deque deque = new ArrayDeque<>(); public void offer(E e) { deque.addLast(e); } public E poll() { return deque.removeFirst(); } public E peek() { return deque.peekFirst(); } public boolean isEmpty() { return deque.isEmpty(); } } // Queue 接口標準方法 Queue queue = new ArrayDeque<>(); queue.offer("a"); queue.offer("b"); queue.poll(); // "a" queue.peek(); // "b"
// 核心字段
transient E[] elements;
transient int head; // 隊首索引
transient int tail; // 隊尾索引 (下一個插入位置)
// addFirst 邏輯
public void addFirst(E e) {
if (e == null) throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e; // 循環數組取模
if (head == tail) doubleCapacity(); // 觸發擴容
}
// removeFirst 邏輯
public E removeFirst() {
E x = pollFirst();
if (x == null) throw new NoSuchElementException();
return x;
}
public E pollFirst() {
int h = head;
E result = elements[h];
if (result == null) return null; // 空隊列
elements[h] = null; // 幫助 GC
head = (h + 1) & (elements.length - 1);
return result;
}
// 擴容策略:2倍,保持元素邏輯順序
private void doubleCapacity() {
int h = head, n = elements.length;
int r = n - h; // head 到末尾的元素數
E[] a = (E[]) new Object[n << 1];
System.arraycopy(elements, h, a, 0, r);
System.arraycopy(elements, 0, a, r, h);
elements = a;
head = 0;
tail = n;
}
// 題目:找出不被其他數"覆蓋"的關鍵數,降序輸出
// 核心邏輯:用 ArrayDeque 存輸入,TreeSet 自動去重排序
public class CallatzKeyNumbers {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int k = sc.nextInt();
Deque input = new ArrayDeque<>(k);
for (int i = 0; i < k; i++) input.add(sc.nextInt());
Set covered = new HashSet<>();
for (int n : input) {
int t = n;
while (t != 1) {
t = (t % 2 == 0) ? t / 2 : (3 * t + 1) / 2;
if (input.contains(t)) covered.add(t); // 被覆蓋
}
}
// TreeSet 自然升序,最後反轉輸出
Set keys = new TreeSet<>();
for (int n : input) if (!covered.contains(n)) keys.add(n);
keys.stream().sorted(Comparator.reverseOrder())
.forEach(n -> System.out.print(n + " "));
}
}
| 操作 | ArrayDeque | Stack (Vector) | LinkedList |
|---|---|---|---|
| push/pop (棧) | ~1.2 ns/op | ~3.5 ns/op (同步) | ~2.8 ns/op |
| offer/poll (隊列) | ~1.3 ns/op | N/A | ~3.0 ns/op |
| 記憶體/元素 | ~4 bytes (引用) | ~4 bytes | ~24 bytes (節點對象) |
ConcurrentLinkedDeque 或外部鎖保護 ArrayDequenew ArrayDeque<>(initialCapacity) 減少擴容Stack 類 (Java 官方文檔建議用 Deque 替代)