【数据结构】队列(Queue)全面详解

目录

[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 具体使用示例)

LinkedList作为队列

ArrayDeque的高性能队列

[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 有界阻塞,控制资源
相关推荐
猷咪5 分钟前
C++基础
开发语言·c++
IT·小灰灰6 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧8 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q9 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳09 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾9 分钟前
php 对接deepseek
android·开发语言·php
vx_BS8133013 分钟前
【直接可用源码免费送】计算机毕业设计精选项目03574基于Python的网上商城管理系统设计与实现:Java/PHP/Python/C#小程序、单片机、成品+文档源码支持定制
java·python·课程设计
2601_9498683613 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
飞机和胖和黄25 分钟前
考研之王道C语言第三周
c语言·数据结构·考研
星火开发设计26 分钟前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识