跳到主要内容

Java Queue 与 Deque

Queue(队列)和 Deque(双端队列)是 Java 集合框架中用于实现队列数据结构的接口。理解队列的使用是处理 FIFO 和双端操作的基础。本章将详细介绍 Java 中的队列。

Queue 接口与实现(LinkedList、PriorityQueue)

Queue 接口

**Queue**是队列接口,遵循 FIFO(First In First Out,先进先出)原则。

核心方法

操作抛出异常返回特殊值
插入add(e)offer(e)
删除remove()poll()
查看element()peek()

LinkedList 作为 Queue

LinkedList 实现了 Queue 接口,可以作为队列使用。

import java.util.LinkedList;
import java.util.Queue;

Queue<String> queue = new LinkedList<>();

// 添加元素(推荐使用 offer)
queue.offer("first");
queue.offer("second");
queue.offer("third");

// 查看队首元素(不删除)
String head = queue.peek(); // "first"

// 删除并返回队首元素
String removed = queue.poll(); // "first"

PriorityQueue(优先级队列)

**PriorityQueue**是基于堆实现的优先级队列,元素按优先级排序。

import java.util.PriorityQueue;

// 自然排序(升序)
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(4);
pq.offer(1);
pq.offer(5);

// 按优先级取出(最小的先出)
while (!pq.isEmpty()) {
System.out.println(pq.poll()); // 1, 1, 3, 4, 5
}

// 自定义排序(降序)
PriorityQueue<Integer> pqDesc = new PriorityQueue<>(Collections.reverseOrder());
pqDesc.offer(3);
pqDesc.offer(1);
pqDesc.offer(4);

while (!pqDesc.isEmpty()) {
System.out.println(pqDesc.poll()); // 4, 3, 1
}

Queue 的常用方法

Queue<String> queue = new LinkedList<>();

// 添加元素
boolean added = queue.offer("item"); // 推荐:返回 boolean
// queue.add("item"); // 不推荐:失败时抛出异常

// 删除元素
String removed = queue.poll(); // 推荐:返回 null(如果为空)
// String removed = queue.remove(); // 不推荐:失败时抛出异常

// 查看元素
String head = queue.peek(); // 推荐:返回 null(如果为空)
// String head = queue.element(); // 不推荐:失败时抛出异常

// 检查
boolean empty = queue.isEmpty();
int size = queue.size();

Deque 接口(ArrayDeque)

Deque 接口

**Deque(Double Ended Queue)**是双端队列,支持在两端进行插入和删除操作。

特点

  • 可以作为队列使用(FIFO)
  • 可以作为栈使用(LIFO)
  • 支持在两端操作

ArrayDeque

**ArrayDeque**是基于数组实现的双端队列。

特点

  • 性能好:比 LinkedList 性能更好
  • 无容量限制:自动扩容
  • 线程不安全:多线程环境下需要同步
  • 不允许 null:不能存储 null 元素
import java.util.ArrayDeque;
import java.util.Deque;

Deque<String> deque = new ArrayDeque<>();

// 作为队列使用(FIFO)
deque.offerLast("first");
deque.offerLast("second");
String first = deque.pollFirst(); // "first"

// 作为栈使用(LIFO)
deque.push("first");
deque.push("second");
String top = deque.pop(); // "second"

常用操作方法(offer, poll, peek, push, pop)

Queue 方法

Queue<String> queue = new LinkedList<>();

// offer:添加元素到队尾
queue.offer("first");
queue.offer("second");

// poll:删除并返回队首元素
String head = queue.poll(); // "first"

// peek:查看队首元素(不删除)
String next = queue.peek(); // "second"

Deque 方法

队列操作(FIFO)

Deque<String> deque = new ArrayDeque<>();

// 队尾添加
deque.offerLast("first");
deque.offerLast("second");

// 队首删除
String first = deque.pollFirst(); // "first"

// 队首查看
String next = deque.peekFirst(); // "second"

栈操作(LIFO)

Deque<String> stack = new ArrayDeque<>();

// 入栈
stack.push("first");
stack.push("second");

// 出栈
String top = stack.pop(); // "second"

// 查看栈顶
String peek = stack.peek(); // "first"

双端操作

Deque<String> deque = new ArrayDeque<>();

// 在队首添加
deque.offerFirst("first");
deque.offerFirst("second");

// 在队尾添加
deque.offerLast("third");

// 从队首删除
String first = deque.pollFirst(); // "second"

// 从队尾删除
String last = deque.pollLast(); // "third"

// 查看队首
String head = deque.peekFirst(); // "first"

// 查看队尾
String tail = deque.peekLast(); // "first"

方法对比

操作QueueDeque(队列)Deque(栈)
添加offer()offerLast()push()
删除poll()pollFirst()pop()
查看peek()peekFirst()peek()

实际示例

示例 1:队列基本操作

import java.util.*;

public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();

// 添加元素
queue.offer("任务1");
queue.offer("任务2");
queue.offer("任务3");

// 处理队列
while (!queue.isEmpty()) {
String task = queue.poll();
System.out.println("处理:" + task);
}
}
}

示例 2:优先级队列

import java.util.*;

public class PriorityQueueExample {
public static void main(String[] args) {
// 按优先级排序的任务队列
PriorityQueue<Task> tasks = new PriorityQueue<>((t1, t2) ->
Integer.compare(t1.getPriority(), t2.getPriority()));

tasks.offer(new Task("低优先级任务", 3));
tasks.offer(new Task("高优先级任务", 1));
tasks.offer(new Task("中优先级任务", 2));

// 按优先级处理
while (!tasks.isEmpty()) {
Task task = tasks.poll();
System.out.println("处理:" + task.getName() + "(优先级:" + task.getPriority() + ")");
}
}
}

示例 3:栈操作

import java.util.*;

public class StackExample {
public static void main(String[] args) {
// 使用 Deque 作为栈
Deque<String> stack = new ArrayDeque<>();

// 入栈
stack.push("first");
stack.push("second");
stack.push("third");

// 出栈
while (!stack.isEmpty()) {
String item = stack.pop();
System.out.println("出栈:" + item);
}
// 输出:third, second, first(后进先出)
}
}

示例 4:双端队列

import java.util.*;

public class DequeExample {
public static void main(String[] args) {
Deque<String> deque = new ArrayDeque<>();

// 两端添加
deque.offerFirst("first");
deque.offerLast("last");
deque.offerFirst("newFirst");
deque.offerLast("newLast");

System.out.println("队列:" + deque); // [newFirst, first, last, newLast]

// 两端删除
String first = deque.pollFirst(); // "newFirst"
String last = deque.pollLast(); // "newLast"

// 两端查看
String head = deque.peekFirst(); // "first"
String tail = deque.peekLast(); // "last"
}
}

示例 5:括号匹配(使用栈)

import java.util.*;

public class BracketMatcher {
public static boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
Map<Character, Character> pairs = new HashMap<>();
pairs.put(')', '(');
pairs.put(']', '[');
pairs.put('}', '{');

for (char c : s.toCharArray()) {
if (pairs.containsValue(c)) {
// 左括号入栈
stack.push(c);
} else if (pairs.containsKey(c)) {
// 右括号匹配
if (stack.isEmpty() || stack.pop() != pairs.get(c)) {
return false;
}
}
}

return stack.isEmpty();
}

public static void main(String[] args) {
System.out.println(isValid("()")); // true
System.out.println(isValid("()[]{}")); // true
System.out.println(isValid("(]")); // false
System.out.println(isValid("([)]")); // false
}
}

Queue 和 Deque 的选择

使用 Queue

  • 只需要 FIFO 队列
  • 不需要双端操作
  • 使用 LinkedList 或 PriorityQueue

使用 Deque

  • 需要双端操作
  • 需要作为栈使用
  • 使用 ArrayDeque(性能更好)

使用 ArrayDeque vs LinkedList

ArrayDeque

  • 性能更好
  • 不允许 null
  • 适合作为栈和队列

LinkedList

  • 功能更多(实现了 List)
  • 允许 null
  • 适合需要 List 功能的场景

小结

Java Queue 与 Deque 要点:

  • Queue:FIFO 队列,使用 offer/poll/peek
  • PriorityQueue:优先级队列,按优先级排序
  • Deque:双端队列,支持两端操作
  • ArrayDeque:基于数组的双端队列,性能好
  • 栈操作:使用 push/pop/peek

关键要点

  • Queue 遵循 FIFO 原则
  • PriorityQueue 按优先级排序
  • Deque 支持双端操作
  • ArrayDeque 性能优于 LinkedList
  • 可以使用 Deque 实现栈

理解了 Queue 和 Deque,你就能处理队列和栈的数据结构。在下一章,我们将学习 Java 集合的遍历与排序。