目录
[1. 队列的基本概念](#1. 队列的基本概念)
[1.1 队列的定义](#1.1 队列的定义)
[1.2 队列的核心特性](#1.2 队列的核心特性)
[1.3 现实生活中的类比](#1.3 现实生活中的类比)
[2. 队列的抽象数据类型(ADT)](#2. 队列的抽象数据类型(ADT))
[2.1 基本操作接口](#2.1 基本操作接口)
[2.2 操作示例](#2.2 操作示例)
[3. 队列的实现方式](#3. 队列的实现方式)
[3.1 基于数组的实现(顺序队列)](#3.1 基于数组的实现(顺序队列))
[3.1.1 固定大小的顺序队列](#3.1.1 固定大小的顺序队列)
[3.1.2 动态扩容的顺序队列](#3.1.2 动态扩容的顺序队列)
[3.2 基于链表的实现(链式队列)](#3.2 基于链表的实现(链式队列))
[4. Java中的队列实现类](#4. Java中的队列实现类)
[4.1 Queue接口的继承体系](#4.1 Queue接口的继承体系)
[4.2 主要实现类对比](#4.2 主要实现类对比)
[4.3 具体使用示例](#4.3 具体使用示例)
[5. 队列的变种和扩展](#5. 队列的变种和扩展)
[5.1 双端队列(Deque - Double Ended Queue)](#5.1 双端队列(Deque - Double Ended Queue))
[5.2 优先队列(PriorityQueue)](#5.2 优先队列(PriorityQueue))
[5.3 阻塞队列(BlockingQueue)](#5.3 阻塞队列(BlockingQueue))
[5.4 循环队列(Circular Queue)](#5.4 循环队列(Circular Queue))
[6. 队列的应用场景](#6. 队列的应用场景)
[6.1 广度优先搜索(BFS)](#6.1 广度优先搜索(BFS))
[6.2 任务调度系统](#6.2 任务调度系统)
[6.3 消息队列模拟](#6.3 消息队列模拟)
[6.4 缓存淘汰策略(FIFO)](#6.4 缓存淘汰策略(FIFO))
[7. 队列相关的算法题目](#7. 队列相关的算法题目)
[7.1 用队列实现栈](#7.1 用队列实现栈)
[7.2 用栈实现队列](#7.2 用栈实现队列)
[7.3 滑动窗口最大值](#7.3 滑动窗口最大值)
[8. 队列的性能分析](#8. 队列的性能分析)
[8.1 时间复杂度分析](#8.1 时间复杂度分析)
[8.2 空间复杂度优化](#8.2 空间复杂度优化)
[9. 队列的线程安全考虑](#9. 队列的线程安全考虑)
[9.1 并发队列选择](#9.1 并发队列选择)
[9.2 线程安全示例](#9.2 线程安全示例)
[10. 队列选择指南](#10. 队列选择指南)
1. 队列的基本概念
1.1 队列的定义
队列是一种先进先出(FIFO, First-In-First-Out) 的线性数据结构。它只允许在表的一端进行插入操作,在另一端进行删除操作。
1.2 队列的核心特性
-
先进先出原则:最先进入队列的元素将最先被移除
-
两端操作:只能在一端(队尾)添加元素,在另一端(队首)移除元素
-
有序性:元素按照进入的顺序排队
1.3 现实生活中的类比
排队买票场景:
队尾(入队) → [顾客A][顾客B][顾客C][顾客D] → 队首(出队)
后到的人排在队尾 排队中 先到的人在队首
2. 队列的抽象数据类型(ADT)
2.1 基本操作接口
操作 | 方法签名 | 描述 | 异常处理 | 返回特殊值 |
---|---|---|---|---|
入队 | boolean add(E e) |
添加元素到队尾 | 失败抛异常 | boolean offer(E e) |
出队 | E remove() |
移除并返回队首元素 | 失败抛异常 | E poll() |
查看队首 | E element() |
返回队首元素(不移除) | 失败抛异常 | E peek() |
判空 | boolean isEmpty() |
判断队列是否为空 | - | - |
大小 | int size() |
返回队列元素个数 | - | - |
2.2 操作示例
Queue<String> queue = new LinkedList<>();
// 入队操作
queue.offer("A");
queue.offer("B");
queue.offer("C");
// 队列状态: [A, B, C] ← 队尾
// 查看队首
System.out.println("队首元素: " + queue.peek()); // A
// 出队操作
while (!queue.isEmpty()) {
String element = queue.poll();
System.out.println("出队: " + element);
}
// 输出: A, B, C (先进先出)
3. 队列的实现方式
3.1 基于数组的实现(顺序队列)
3.1.1 固定大小的顺序队列
public class ArrayQueue<E> {
private E[] array;
private int front; // 队首指针
private int rear; // 队尾指针
private int size; // 元素个数
private final int capacity;
@SuppressWarnings("unchecked")
public ArrayQueue(int capacity) {
this.capacity = capacity;
this.array = (E[]) new Object[capacity];
this.front = 0;
this.rear = -1;
this.size = 0;
}
public boolean offer(E element) {
if (isFull()) return false;
rear = (rear + 1) % capacity; // 循环利用数组空间
array[rear] = element;
size++;
return true;
}
public E poll() {
if (isEmpty()) return null;
E element = array[front];
array[front] = null; // 帮助垃圾回收
front = (front + 1) % capacity;
size--;
return element;
}
public E peek() {
if (isEmpty()) return null;
return array[front];
}
public boolean isEmpty() { return size == 0; }
public boolean isFull() { return size == capacity; }
public int size() { return size; }
}
3.1.2 动态扩容的顺序队列
public class DynamicArrayQueue<E> {
private E[] array;
private int front;
private int rear;
private int size;
private static final int DEFAULT_CAPACITY = 10;
@SuppressWarnings("unchecked")
public DynamicArrayQueue() {
this.array = (E[]) new Object[DEFAULT_CAPACITY];
this.front = 0;
this.rear = -1;
this.size = 0;
}
public boolean offer(E element) {
if (isFull()) {
resize(); // 自动扩容
}
rear = (rear + 1) % array.length;
array[rear] = element;
size++;
return true;
}
@SuppressWarnings("unchecked")
private void resize() {
int newCapacity = array.length * 2;
E[] newArray = (E[]) new Object[newCapacity];
// 将元素按顺序复制到新数组
for (int i = 0; i < size; i++) {
newArray[i] = array[(front + i) % array.length];
}
array = newArray;
front = 0;
rear = size - 1;
}
}
3.2 基于链表的实现(链式队列)
public class LinkedQueue<E> {
// 节点定义
private static class Node<E> {
E data;
Node<E> next;
Node(E data) {
this.data = data;
}
}
private Node<E> front; // 队首节点
private Node<E> rear; // 队尾节点
private int size;
public LinkedQueue() {
front = rear = null;
size = 0;
}
public boolean offer(E element) {
Node<E> newNode = new Node<>(element);
if (isEmpty()) {
front = rear = newNode;
} else {
rear.next = newNode;
rear = newNode;
}
size++;
return true;
}
public E poll() {
if (isEmpty()) return null;
E element = front.data;
front = front.next;
if (front == null) {
rear = null; // 队列为空时,rear也要置空
}
size--;
return element;
}
public E peek() {
if (isEmpty()) return null;
return front.data;
}
public boolean isEmpty() { return front == null; }
public int size() { return size; }
}
4. Java中的队列实现类
4.1 Queue接口的继承体系
Collection ← Queue ← Deque ← LinkedList/ArrayDeque
4.2 主要实现类对比
实现类 | 底层结构 | 线程安全 | 特性 | 适用场景 |
---|---|---|---|---|
LinkedList | 双向链表 | 否 | 可作队列/双端队列 | 一般队列需求 |
ArrayDeque | 循环数组 | 否 | 高性能,容量可调 | 推荐的标准队列 |
PriorityQueue | 堆(数组) | 否 | 元素按优先级出队 | 优先队列 |
ConcurrentLinkedQueue | 链表 | 是 | 高并发非阻塞 | 高并发场景 |
ArrayBlockingQueue | 数组 | 是 | 有界阻塞队列 | 生产者-消费者 |
LinkedBlockingQueue | 链表 | 是 | 可选有界阻塞队列 | 生产者-消费者 |
4.3 具体使用示例
LinkedList作为队列
Queue<String> queue = new LinkedList<>();
// 基本操作
queue.offer("A");
queue.offer("B");
queue.offer("C");
System.out.println("队首元素: " + queue.peek()); // A
System.out.println("出队: " + queue.poll()); // A
System.out.println("队列大小: " + queue.size()); // 2
ArrayDeque的高性能队列
Queue<Integer> queue = new ArrayDeque<>(100); // 预分配容量
// 批量操作性能更好
for (int i = 0; i < 1000; i++) {
queue.offer(i);
}
while (!queue.isEmpty()) {
Integer num = queue.poll();
// 处理任务
}
5. 队列的变种和扩展
5.1 双端队列(Deque - Double Ended Queue)
Deque<String> deque = new ArrayDeque<>();
// 作为栈使用(后进先出)
deque.push("A"); // 添加到队首
deque.push("B");
deque.push("C");
System.out.println("弹出: " + deque.pop()); // C
// 作为队列使用(先进先出)
deque.offerLast("X"); // 添加到队尾
deque.offerLast("Y");
System.out.println("出队: " + deque.pollFirst()); // X
// 双端操作
deque.offerFirst("Z"); // 添加到队首
deque.offerLast("W"); // 添加到队尾
5.2 优先队列(PriorityQueue)
// 自然顺序(最小堆)
Queue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(5);
minHeap.offer(1);
minHeap.offer(3);
minHeap.offer(2);
minHeap.offer(4);
System.out.println("出队顺序:");
while (!minHeap.isEmpty()) {
System.out.print(minHeap.poll() + " "); // 1 2 3 4 5
}
// 自定义优先级
Queue<String> lengthQueue = new PriorityQueue<>(
(a, b) -> a.length() - b.length() // 按字符串长度排序
);
lengthQueue.offer("apple");
lengthQueue.offer("banana");
lengthQueue.offer("cat");
while (!lengthQueue.isEmpty()) {
System.out.println(lengthQueue.poll()); // cat, apple, banana
}
5.3 阻塞队列(BlockingQueue)
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// 生产者线程
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
queue.put(i); // 如果队列满,会阻塞等待
System.out.println("生产: " + i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
// 消费者线程
new Thread(() -> {
try {
while (true) {
Integer item = queue.take(); // 如果队列空,会阻塞等待
System.out.println("消费: " + item);
Thread.sleep(150);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
5.4 循环队列(Circular Queue)
public class CircularQueue {
private int[] data;
private int front;
private int rear;
private int size;
private final int capacity;
public CircularQueue(int k) {
capacity = k;
data = new int[capacity];
front = 0;
rear = -1;
size = 0;
}
public boolean enQueue(int value) {
if (isFull()) return false;
rear = (rear + 1) % capacity;
data[rear] = value;
size++;
return true;
}
public boolean deQueue() {
if (isEmpty()) return false;
front = (front + 1) % capacity;
size--;
return true;
}
public int Front() {
return isEmpty() ? -1 : data[front];
}
public int Rear() {
return isEmpty() ? -1 : data[rear];
}
public boolean isEmpty() { return size == 0; }
public boolean isFull() { return size == capacity; }
}
6. 队列的应用场景
6.1 广度优先搜索(BFS)
// 二叉树的层次遍历
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelSize = queue.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(level);
}
return result;
}
// 图的BFS
public void bfs(Graph graph, int start) {
boolean[] visited = new boolean[graph.size()];
Queue<Integer> queue = new LinkedList<>();
visited[start] = true;
queue.offer(start);
while (!queue.isEmpty()) {
int node = queue.poll();
System.out.println("访问节点: " + node);
for (int neighbor : graph.getNeighbors(node)) {
if (!visited[neighbor]) {
visited[neighbor] = true;
queue.offer(neighbor);
}
}
}
}
6.2 任务调度系统
public class TaskScheduler {
private final Queue<Runnable> taskQueue = new LinkedList<>();
private final ExecutorService executor = Executors.newFixedThreadPool(4);
private volatile boolean isRunning = true;
public void submitTask(Runnable task) {
synchronized (taskQueue) {
taskQueue.offer(task);
taskQueue.notifyAll(); // 唤醒等待的消费者线程
}
}
public void start() {
for (int i = 0; i < 4; i++) {
executor.execute(this::processTasks);
}
}
private void processTasks() {
while (isRunning) {
Runnable task;
synchronized (taskQueue) {
while (taskQueue.isEmpty() && isRunning) {
try {
taskQueue.wait(); // 等待新任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
if (!isRunning) return;
task = taskQueue.poll();
}
// 执行任务
try {
task.run();
} catch (Exception e) {
System.err.println("任务执行异常: " + e.getMessage());
}
}
}
public void shutdown() {
isRunning = false;
synchronized (taskQueue) {
taskQueue.notifyAll();
}
executor.shutdown();
}
}
6.3 消息队列模拟
public class MessageQueue {
private final Queue<String> queue = new LinkedList<>();
private final int maxSize;
private final Object lock = new Object();
public MessageQueue(int maxSize) {
this.maxSize = maxSize;
}
// 生产者
public void produce(String message) throws InterruptedException {
synchronized (lock) {
while (queue.size() == maxSize) {
System.out.println("队列已满,生产者等待...");
lock.wait();
}
queue.offer(message);
System.out.println("生产消息: " + message + ",当前队列大小: " + queue.size());
lock.notifyAll(); // 唤醒消费者
}
}
// 消费者
public String consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
System.out.println("队列为空,消费者等待...");
lock.wait();
}
String message = queue.poll();
System.out.println("消费消息: " + message + ",当前队列大小: " + queue.size());
lock.notifyAll(); // 唤醒生产者
return message;
}
}
}
6.4 缓存淘汰策略(FIFO)
public class FIFOCache<K, V> {
private final int capacity;
private final Queue<K> keyQueue;
private final Map<K, V> cache;
public FIFOCache(int capacity) {
this.capacity = capacity;
this.keyQueue = new LinkedList<>();
this.cache = new HashMap<>();
}
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
if (cache.containsKey(key)) {
// 更新现有键的值
cache.put(key, value);
return;
}
if (keyQueue.size() == capacity) {
// 淘汰最早的元素
K oldestKey = keyQueue.poll();
cache.remove(oldestKey);
System.out.println("淘汰键: " + oldestKey);
}
// 添加新元素
keyQueue.offer(key);
cache.put(key, value);
System.out.println("添加键: " + key);
}
public void display() {
System.out.println("当前缓存内容:");
for (K key : keyQueue) {
System.out.println(key + " -> " + cache.get(key));
}
}
}
7. 队列相关的算法题目
7.1 用队列实现栈
class MyStack {
private Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
queue.offer(x);
// 将前面的元素重新入队,让新元素在队首
int size = queue.size();
for (int i = 0; i < size - 1; i++) {
queue.offer(queue.poll());
}
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
7.2 用栈实现队列
class MyQueue {
private Stack<Integer> inStack;
private Stack<Integer> outStack;
public MyQueue() {
inStack = new Stack<>();
outStack = new Stack<>();
}
public void push(int x) {
inStack.push(x);
}
public int pop() {
if (outStack.isEmpty()) {
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
return outStack.pop();
}
public int peek() {
if (outStack.isEmpty()) {
while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
}
}
return outStack.peek();
}
public boolean empty() {
return inStack.isEmpty() && outStack.isEmpty();
}
}
7.3 滑动窗口最大值
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0) return new int[0];
int n = nums.length;
int[] result = new int[n - k + 1];
Deque<Integer> deque = new ArrayDeque<>(); // 存储索引
for (int i = 0; i < n; i++) {
// 移除超出窗口范围的元素
while (!deque.isEmpty() && deque.peekFirst() < i - k + 1) {
deque.pollFirst();
}
// 移除比当前元素小的元素,保持递减顺序
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;
}
8. 队列的性能分析
8.1 时间复杂度分析
操作 | 基于数组 | 基于链表 | 说明 |
---|---|---|---|
入队 (enqueue) | O(1) 平均 | O(1) | 尾部添加 |
出队 (dequeue) | O(1) | O(1) | 头部移除 |
查看队首 (peek) | O(1) | O(1) | 访问头部 |
查找 (contains) | O(n) | O(n) | 需要遍历 |
空间复杂度 | O(n) | O(n) | 存储n个元素 |
注意 :PriorityQueue
的入队出队时间复杂度为 O(log n)
8.2 空间复杂度优化
循环数组的优势
// 循环数组避免数据搬移,提高性能
public class CircularArrayQueue {
private int[] data;
private int head; // 队头索引
private int tail; // 队尾索引
private int size; // 元素个数
public boolean enqueue(int item) {
if (size == data.length) return false;
data[tail] = item;
tail = (tail + 1) % data.length; // 循环利用
size++;
return true;
}
}
9. 队列的线程安全考虑
9.1 并发队列选择
场景 | 推荐实现 | 特点 |
---|---|---|
高并发读多写少 | ConcurrentLinkedQueue |
非阻塞,高性能 |
生产者-消费者 | ArrayBlockingQueue |
有界,阻塞操作 |
高吞吐量 | LinkedBlockingQueue |
可选有界,吞吐量高 |
延迟任务 | DelayQueue |
元素按延迟时间排序 |
优先级任务 | PriorityBlockingQueue |
线程安全的优先队列 |
9.2 线程安全示例
// 使用ConcurrentLinkedQueue
Queue<String> concurrentQueue = new ConcurrentLinkedQueue<>();
// 多线程安全操作
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
final int taskId = i;
executor.submit(() -> {
concurrentQueue.offer("Task-" + taskId);
String task = concurrentQueue.poll();
// 处理任务...
});
}
10. 队列选择指南
需求场景 | 推荐实现 | 理由 |
---|---|---|
一般队列需求 | ArrayDeque |
性能最好,内存连续 |
需要双端操作 | ArrayDeque |
支持栈和队列操作 |
需要优先级 | PriorityQueue |
按优先级出队 |
高并发场景 | ConcurrentLinkedQueue |
非阻塞线程安全 |
生产者-消费者 | ArrayBlockingQueue |
有界阻塞,控制资源 |