1. 什么是 Deque?
Deque(Double Ended Queue,双端队列)是 Java Collections Framework 的一部分,它支持在队列的两端进行插入和删除操作。
2. Deque 的特点
-
双端操作:可以从头部和尾部添加/删除元素
-
可用作多种数据结构:
-
普通队列(FIFO)
-
栈(LIFO)
-
双端队列
-
3. 主要实现类
java
// ArrayDeque - 基于数组实现,性能较好,推荐使用
Deque<String> arrayDeque = new ArrayDeque<>();
// LinkedList - 基于链表实现,也实现了Deque接口
Deque<String> linkedListDeque = new LinkedList<>();
// ConcurrentLinkedDeque - 线程安全版本(java.util.concurrent)
Deque<String> concurrentDeque = new ConcurrentLinkedDeque<>();
4. 常用操作方法
4.1 添加元素
java
Deque<Integer> deque = new ArrayDeque<>();
// 头部操作
deque.addFirst(1); // 抛出异常
deque.offerFirst(2); // 返回boolean
// 尾部操作
deque.addLast(3); // 抛出异常
deque.offerLast(4); // 返回boolean
// 等价方法
deque.add(5); // addLast()
deque.offer(6); // offerLast()
deque.push(7); // addFirst() - 栈操作
4.2 删除元素
java
// 头部删除
int first1 = deque.removeFirst(); // 抛出异常
int first2 = deque.pollFirst(); // 返回null
// 尾部删除
int last1 = deque.removeLast(); // 抛出异常
int last2 = deque.pollLast(); // 返回null
// 等价方法
int elem1 = deque.remove(); // removeFirst()
int elem2 = deque.poll(); // pollFirst()
int elem3 = deque.pop(); // removeFirst() - 栈操作
4.3 查看元素(不删除)
java
// 查看头部
int head1 = deque.getFirst(); // 抛出异常
int head2 = deque.peekFirst(); // 返回null
int head3 = deque.element(); // getFirst()
int head4 = deque.peek(); // peekFirst()
// 查看尾部
int tail1 = deque.getLast(); // 抛出异常
int tail2 = deque.peekLast(); // 返回null
5. 使用示例
示例1:作为栈使用
java
Deque<Integer> stack = new ArrayDeque<>();
// 入栈
stack.push(1);
stack.push(2);
stack.push(3);
// 出栈
while (!stack.isEmpty()) {
System.out.println(stack.pop()); // 输出: 3, 2, 1
}
示例2:作为队列使用
java
Deque<String> queue = new ArrayDeque<>();
// 入队
queue.offer("A");
queue.offer("B");
queue.offer("C");
// 出队
while (!queue.isEmpty()) {
System.out.println(queue.poll()); // 输出: A, B, C
}
示例3:双端操作
java
Deque<Character> deque = new ArrayDeque<>();
// 两端添加
deque.addFirst('B');
deque.addLast('C');
deque.addFirst('A');
deque.addLast('D');
// 遍历
for (char c : deque) {
System.out.print(c + " "); // 输出: A B C D
}
// 两端删除
System.out.println(deque.removeFirst()); // A
System.out.println(deque.removeLast()); // D
6. ArrayDeque vs LinkedList
| 特性 | ArrayDeque | LinkedList |
|---|---|---|
| 数据结构 | 可扩展数组 | 双向链表 |
| 内存使用 | 更紧凑 | 每个元素额外存储前后指针 |
| 性能 | 随机访问快 | 插入删除快(指定位置) |
| 推荐使用 | 大多数场景 | 需要频繁在中间操作时 |
7. 实际应用场景
java
// 场景1:滑动窗口最大值
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> deque = new ArrayDeque<>();
int[] result = new int[nums.length - k + 1];
for (int i = 0; i < nums.length; i++) {
// 移除超出窗口的元素
if (!deque.isEmpty() && deque.peekFirst() == i - k) {
deque.pollFirst();
}
// 保持deque递减
while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) {
deque.pollLast();
}
deque.offerLast(i);
// 记录窗口最大值
if (i >= k - 1) {
result[i - k + 1] = nums[deque.peekFirst()];
}
}
return result;
}
// 场景2:括号匹配检查
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
} else {
if (stack.isEmpty()) return false;
char top = stack.pop();
if ((c == ')' && top != '(') ||
(c == ']' && top != '[') ||
(c == '}' && top != '{')) {
return false;
}
}
}
return stack.isEmpty();
}
8. 注意事项
-
容量限制:ArrayDeque 有初始容量,可自动扩容
-
空值处理:
-
addFirst/addLast:不接受 null(会抛出 NPE) -
offerFirst/offerLast:不接受 null
-
-
线程安全:ArrayDeque 和 LinkedList 都不是线程安全的
-
性能考虑:ArrayDeque 通常比 LinkedList 性能更好
总结
Deque 是一个非常实用的接口,它提供了队列和栈的完整功能。在大多数情况下,推荐使用 ArrayDeque 作为实现类,因为它比 LinkedList 有更好的性能表现。