数据结构 - Java 队列

Java中的队列

队列是Java集合框架中的一种重要数据结构,用于按照特定顺序存储和处理元素,通常遵循先进先出(FIFO)原则。Java提供了丰富的队列实现,适用于不同场景。

Queue接口

Queue是Java集合框架中的一个基础接口,继承自Collection接口,定义了队列的基本操作:

java 复制代码
import java.util.Queue;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.PriorityQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.Comparator;
import java.util.Deque;
import java.util.concurrent.PriorityBlockingQueue;

public class JavaQueueExamples {

    public static void main(String[] args) {
        // 1. 基本队列操作示例
        basicQueueOperations();
        
        // 2. 常用队列实现示例
        queueImplementations();
        
        // 3. 阻塞队列示例
        blockingQueueExample();
        
        // 4. 延迟队列示例
        delayQueueExample();
        
        // 5. 双端队列示例
        dequeExample();
        
        // 6. 优先级队列示例
        priorityQueueExample();
    }
    
    // 1. 基本队列操作
    public static void basicQueueOperations() {
        System.out.println("\n=== 基本队列操作 ===");
        
        Queue<String> queue = new LinkedList<>();
        
        // 添加元素
        queue.add("第一个"); // 添加成功返回true,队列满则抛出异常
        queue.offer("第二个"); // 添加成功返回true,队列满则返回false
        
        // 查看队首元素但不移除
        System.out.println("队首元素(peek): " + queue.peek()); // 队列为空返回null
        System.out.println("队首元素(element): " + queue.element()); // 队列为空抛出异常
        
        // 移除并返回队首元素
        System.out.println("移除队首(poll): " + queue.poll()); // 队列为空返回null
        System.out.println("移除队首(remove): " + queue.remove()); // 队列为空抛出异常
        
        System.out.println("队列是否为空: " + queue.isEmpty());
    }
    
    // 2. 常用队列实现
    public static void queueImplementations() {
        System.out.println("\n=== 常用队列实现 ===");
        
        // LinkedList实现的队列
        Queue<String> linkedListQueue = new LinkedList<>();
        linkedListQueue.offer("LinkedList队列元素1");
        linkedListQueue.offer("LinkedList队列元素2");
        System.out.println("LinkedList队列: " + linkedListQueue);
        
        // ArrayDeque实现的队列 (更高效)
        Queue<String> arrayDequeQueue = new ArrayDeque<>();
        arrayDequeQueue.offer("ArrayDeque队列元素1");
        arrayDequeQueue.offer("ArrayDeque队列元素2");
        System.out.println("ArrayDeque队列: " + arrayDequeQueue);
    }
    
    // 3. 阻塞队列示例
    public static void blockingQueueExample() {
        System.out.println("\n=== 阻塞队列示例 ===");
        
        // 有界阻塞队列
        BlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(2);
        
        try {
            arrayBlockingQueue.put("任务1");
            arrayBlockingQueue.put("任务2");
            System.out.println("ArrayBlockingQueue: " + arrayBlockingQueue);
            
            // 如果队列已满,put方法会阻塞
            // arrayBlockingQueue.put("任务3"); // 会阻塞直到有空间
            
            // 使用offer方法添加,可以设置超时时间
            boolean added = arrayBlockingQueue.offer("任务3", 1, TimeUnit.SECONDS);
            System.out.println("添加任务3是否成功: " + added);
            
            // 取出元素
            String task = arrayBlockingQueue.take(); // 如果队列为空,take方法会阻塞
            System.out.println("取出任务: " + task);
            
            // 使用poll方法取出,可以设置超时时间
            String task2 = arrayBlockingQueue.poll(1, TimeUnit.SECONDS);
            System.out.println("取出任务2: " + task2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        // 无界阻塞队列
        BlockingQueue<String> linkedBlockingQueue = new LinkedBlockingQueue<>();
        linkedBlockingQueue.offer("LinkedBlockingQueue元素");
        System.out.println("LinkedBlockingQueue: " + linkedBlockingQueue);
    }
    
    // 4. 延迟队列示例
    public static void delayQueueExample() {
        System.out.println("\n=== 延迟队列示例 ===");
        
        DelayQueue<DelayedElement> delayQueue = new DelayQueue<>();
        
        // 添加延迟元素,分别延迟1秒、2秒、3秒
        delayQueue.offer(new DelayedElement("任务1", 1000));
        delayQueue.offer(new DelayedElement("任务2", 2000));
        delayQueue.offer(new DelayedElement("任务3", 3000));
        
        System.out.println("延迟队列大小: " + delayQueue.size());
        
        try {
            // 尝试获取,但只有延迟到期的元素才能被取出
            System.out.println("开始获取延迟队列元素...");
            
            // 获取并移除第一个可用的元素
            DelayedElement element1 = delayQueue.take();
            System.out.println("取出元素: " + element1.getName() + ", 时间: " + System.currentTimeMillis());
            
            // 获取并移除第二个可用的元素
            DelayedElement element2 = delayQueue.take();
            System.out.println("取出元素: " + element2.getName() + ", 时间: " + System.currentTimeMillis());
            
            // 使用poll带超时的方法获取第三个元素
            DelayedElement element3 = delayQueue.poll(5, TimeUnit.SECONDS);
            if (element3 != null) {
                System.out.println("取出元素: " + element3.getName() + ", 时间: " + System.currentTimeMillis());
            } else {
                System.out.println("超时未获取到元素");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    // 5. 双端队列示例
    public static void dequeExample() {
        System.out.println("\n=== 双端队列示例 ===");
        
        Deque<String> deque = new ArrayDeque<>();
        
        // 在队首和队尾添加元素
        deque.offerFirst("队首元素1");
        deque.offerLast("队尾元素1");
        deque.offerFirst("队首元素2");
        deque.offerLast("队尾元素2");
        
        System.out.println("双端队列: " + deque); // [队首元素2, 队首元素1, 队尾元素1, 队尾元素2]
        
        // 查看队首和队尾元素
        System.out.println("队首元素: " + deque.peekFirst());
        System.out.println("队尾元素: " + deque.peekLast());
        
        // 移除队首和队尾元素
        System.out.println("移除队首: " + deque.pollFirst());
        System.out.println("移除队尾: " + deque.pollLast());
        
        System.out.println("处理后的双端队列: " + deque);
        
        // 使用栈方法 (LIFO)
        deque.push("栈顶元素"); // 等同于addFirst()
        System.out.println("添加栈顶元素后: " + deque);
        System.out.println("弹出栈顶: " + deque.pop()); // 等同于removeFirst()
        System.out.println("弹出后的队列: " + deque);
    }
    
    // 6. 优先级队列示例
    public static void priorityQueueExample() {
        System.out.println("\n=== 优先级队列示例 ===");
        
        // 自然排序的优先级队列 (小顶堆)
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        minHeap.offer(10);
        minHeap.offer(5);
        minHeap.offer(15);
        minHeap.offer(1);
        
        System.out.print("自然排序优先级队列出队顺序: ");
        while (!minHeap.isEmpty()) {
            System.out.print(minHeap.poll() + " ");
        }
        System.out.println();
        
        // 自定义比较器的优先级队列 (大顶堆)
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
        maxHeap.offer(10);
        maxHeap.offer(5);
        maxHeap.offer(15);
        maxHeap.offer(1);
        
        System.out.print("自定义排序优先级队列出队顺序: ");
        while (!maxHeap.isEmpty()) {
            System.out.print(maxHeap.poll() + " ");
        }
        System.out.println();
        
        // 使用对象和自定义比较器
        PriorityQueue<Task> taskQueue = new PriorityQueue<>((t1, t2) -> t1.getPriority() - t2.getPriority());
        taskQueue.offer(new Task("普通任务", 3));
        taskQueue.offer(new Task("紧急任务", 1));
        taskQueue.offer(new Task("低优先级任务", 5));
        taskQueue.offer(new Task("高优先级任务", 2));
        
        System.out.println("任务优先级队列出队顺序: ");
        while (!taskQueue.isEmpty()) {
            System.out.println(taskQueue.poll());
        }
        
        // 线程安全的优先级阻塞队列
        PriorityBlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();
        priorityBlockingQueue.offer(10);
        priorityBlockingQueue.offer(5);
        priorityBlockingQueue.offer(15);
        System.out.println("PriorityBlockingQueue: " + priorityBlockingQueue);
    }
}

// 延迟队列元素类

java 复制代码
class DelayedElement implements Delayed {
    private String name;
    private long expireTime; // 过期时间,单位毫秒
    
    public DelayedElement(String name, long delayInMillis) {
        this.name = name;
        this.expireTime = System.currentTimeMillis() + delayInMillis;
    }
    
    public String getName() {
        return name;
    }
    
    @Override
    public long getDelay(TimeUnit unit) {
        // 计算剩余延迟时间
        long diff = expireTime - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }
    
    @Override
    public int compareTo(Delayed other) {
        // 比较延迟时间
        if (other == this) {
            return 0;
        }
        if (other instanceof DelayedElement) {
            DelayedElement otherElement = (DelayedElement) other;
            return Long.compare(expireTime, otherElement.expireTime);
        }
        long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS);
        return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1);
    }
    
    @Override
    public String toString() {
        return "DelayedElement{name='" + name + "', expireTime=" + expireTime + "}";
    }
}

// 任务类(用于优先级队列示例)

java 复制代码
class Task {
    private String name;
    private int priority; // 优先级,数字越小优先级越高
    
    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }
    
    public String getName() {
        return name;
    }
    
    public int getPriority() {
        return priority;
    }
    
    @Override
    public String toString() {
        return "Task{name='" + name + "', priority=" + priority + "}";
    }
}

Queue接口的核心方法

Queue接口定义了两组核心操作方法,它们在不同情况下的行为略有不同:

操作抛出异常返回特殊值

java 复制代码
添加元素add(e)offer(e)
移除元素remove()poll()
检查元素element()peek()

常见的队列实现

Java提供了多种队列实现,适合不同的应用场景:

  1. 非阻塞队列

    LinkedList: 基于链表的队列实现,适合频繁添加/删除操作

    ArrayDeque: 基于数组的双端队列,通常比LinkedList性能更好

    PriorityQueue: 优先级队列,基于堆实现,元素按优先级出队

  2. 阻塞队列 (BlockingQueue)

    阻塞队列支持在队列为空/满时阻塞操作,非常适合生产者-消费者模式:

ArrayBlockingQueue: 有界阻塞队列,基于数组实现

LinkedBlockingQueue: 可选有界阻塞队列,基于链表实现

PriorityBlockingQueue: 无界优先级阻塞队列

DelayQueue: 延迟队列,元素只有到达指定延迟时间才能被取出

SynchronousQueue: 没有容量的阻塞队列,每个插入操作必须等待相应的移除操作

  1. 双端队列 (Deque)
    双端队列允许在两端进行插入和移除操作:

ArrayDeque: 基于数组的可调整大小的双端队列

LinkedList: 也实现了Deque接口

LinkedBlockingDeque: 线程安全的双端阻塞队列

队列的应用场景

任务调度:使用DelayQueue或PriorityQueue实现定时任务

线程池:阻塞队列用于存储等待执行的任务

消息队列:作为生产者-消费者之间的缓冲区

资源池:管理共享资源的分配和释放

缓存:实现LRU缓存等缓存策略

广度优先搜索:在图算法中使用队列进行BFS遍历

相关推荐
青桔柠薯片3 分钟前
数据结构:单向链表,顺序栈和链式栈
数据结构·链表
A懿轩A4 分钟前
【Maven 构建工具】从零到上手 Maven:安装配置 + IDEA 集成 + 第一个项目(保姆级教程)
java·maven·intellij-idea
野犬寒鸦13 分钟前
从零起步学习并发编程 || 第一章:初步认识进程与线程
java·服务器·后端·学习
我爱娃哈哈18 分钟前
SpringBoot + Flowable + 自定义节点:可视化工作流引擎,支持请假、报销、审批全场景
java·spring boot·后端
XiaoFan01236 分钟前
将有向工作流图转为结构树的实现
java·数据结构·决策树
睡一觉就好了。1 小时前
快速排序——霍尔排序,前后指针排序,非递归排序
数据结构·算法·排序算法
齐落山大勇1 小时前
数据结构——单链表
数据结构
小突突突1 小时前
浅谈Java中的反射
java·开发语言
Anastasiozzzz1 小时前
LeetCode Hot100 295. 数据流的中位数 MedianFinder
java·服务器·前端
我真的是大笨蛋1 小时前
Redo Log详解
java·数据库·sql·mysql·性能优化