双端队列操作:栈与队列
使用 LinkedList 作为 Deque,通过 push/pop 实现栈行为,通过 offer/poll 实现队列行为
双端队列操作:栈与队列 是 CoddyKit 上的免费 Java Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Java Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Java Academy 课程共包含 4 节课。
双端队列:两端队列
双端队列允许在两端插入和删除元素。Java 的 Deque 接口由 LinkedList 和 ArrayDeque 实现。
import java.util.Deque;
import java.util.ArrayDeque;
Deque<String> deque = new ArrayDeque<>();
deque.addFirst("A"); // front
deque.addLast("B"); // back
deque.addFirst("Z"); // new front
System.out.println(deque); // [Z, A, B]作为双端队列时比较 ArrayDeque 和 LinkedList
通常更推荐将 ArrayDeque 而不是 LinkedList 用作双端队列:
- 没有每个元素对应的节点开销
- 缓存局部性更好
- 栈和队列操作速度略快
只有在同时需要 List 接口时,才选择 LinkedList。
使用双端队列执行栈操作
使用 push(addFirst)和 pop(removeFirst)来模拟 LIFO 栈。请避免使用过时的 Stack 类——它是同步的,并且已经过时。
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println(stack.pop()); // 3
System.out.println(stack.peek()); // 2 (no removal)
System.out.println(stack.pop()); // 2使用双端队列执行队列操作
使用 offer(addLast)和 poll(removeFirst)来模拟 FIFO 队列。offer 失败时返回 false;add 则会抛出异常。
Deque<String> queue = new ArrayDeque<>();
queue.offer("task1");
queue.offer("task2");
queue.offer("task3");
System.out.println(queue.poll()); // task1
System.out.println(queue.poll()); // task2
System.out.println(queue.size()); // 1双端队列方法参考表
双端队列提供两组方法:一组会抛出异常,另一组会返回特殊值:
- addFirst/addLast 与 offerFirst/offerLast
- removeFirst/removeLast 与 pollFirst/pollLast
- getFirst/getLast 与 peekFirst/peekLast
优先使用 offer/poll/peek 这一组方法,以避免对空双端队列操作时抛出异常。
真实示例:使用两个栈实现撤销和重做
双端队列的经典使用场景:撤销历史记录是一个栈,重做记录是另一个栈。
Deque<String> undo = new ArrayDeque<>();
Deque<String> redo = new ArrayDeque<>();
undo.push("type 'Hello'");
undo.push("type ' World'");
String action = undo.pop();
System.out.println("Undone: " + action); // type ' World'
redo.push(action);
System.out.println("Redo top: " + redo.peek()); // type ' World'使用双端队列检查回文
双端队列可以优雅地检查回文——同时比较两端的字符。
Deque<Character> deque = new ArrayDeque<>();
for (char c : "racecar".toCharArray()) deque.add(c);
boolean isPalindrome = true;
while (deque.size() > 1) {
if (!deque.pollFirst().equals(deque.pollLast())) {
isPalindrome = false;
break;
}
}
System.out.println(isPalindrome); // true使用队列实现 BFS
广度优先搜索使用队列。在竞赛编程和图遍历中,ArrayDeque 是实现 BFS 的标准选择。
import java.util.*;
// BFS on a simple adjacency list
Map<Integer,List<Integer>> graph = Map.of(
1, List.of(2,3),
2, List.of(4),
3, List.of(4),
4, List.of()
);
Deque<Integer> queue = new ArrayDeque<>();
Set<Integer> visited = new HashSet<>();
queue.offer(1);
while (!queue.isEmpty()) {
int node = queue.poll();
if (visited.add(node)) {
System.out.print(node + " ");
queue.addAll(graph.get(node));
}
}使用栈实现 DFS
深度优先搜索使用栈。同样,请优先使用 ArrayDeque,而不是过时的 Stack 类。
Deque<Integer> stack = new ArrayDeque<>();
Set<Integer> visited = new HashSet<>();
stack.push(1);
while (!stack.isEmpty()) {
int node = stack.pop();
if (visited.add(node)) {
System.out.print(node + " ");
// push neighbors (will be processed in reverse order)
List<Integer> neighbors = List.of(2, 3); // simplified
for (int n : neighbors) if (!visited.contains(n)) stack.push(n);
}
}带大小检查的有界双端队列
ArrayDeque 会动态增长,但您可以手动限制容量,以模拟有界缓冲区:
Deque<Integer> buffer = new ArrayDeque<>();
int MAX = 3;
for (int i = 1; i <= 5; i++) {
if (buffer.size() >= MAX) {
buffer.pollFirst(); // drop oldest
}
buffer.offerLast(i);
}
System.out.println(buffer); // [3, 4, 5]性能说明
ArrayDeque 使用循环数组,并会在填满时将容量加倍。所有操作的摊销成本都是 O(1)。由于缓存效率更高,它在大多数基准测试中都优于 LinkedList。请不要手动进行同步——并发场景应使用 ConcurrentLinkedDeque 或阻塞队列。
快速检查
对于 LIFO 操作,应优先使用哪个类来替代过时的 Stack?
回顾:双端队列操作
关键要点:
- 双端队列允许在两端以 O(1) 插入和删除元素
- 对于纯栈或队列的使用场景,ArrayDeque 优于 LinkedList
- push/pop → LIFO 栈;offer/poll → FIFO 队列
- 经典用途:撤销/重做、BFS/DFS、滑动窗口、回文检查
- 避免使用过时的 Stack 和 Queue 类
常见问题解答
「双端队列操作:栈与队列」课时是免费的吗?
是的 — 「双端队列操作:栈与队列」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Java Academy 课程的其余内容,请升级到 CoddyKit PRO。 Java Academy 课程共包含 4 节课。
「双端队列操作:栈与队列」这节课中我会学到什么?
使用 LinkedList 作为 Deque,通过 push/pop 实现栈行为,通过 offer/poll 实现队列行为 你通过在浏览器中直接运行的动手代码来练习 Java Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Java Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Java Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「双端队列操作:栈与队列」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Java Academy 课中编写并运行代码吗?
能。每节 Java Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。