当前位置: 首页 > news >正文

深入解析Java中的双向队列(Deque):操作、实现与应用

双向队列(Deque,全称Double-Ended Queue)是一种允许在队列的头部和尾部高效插入、删除和访问元素的数据结构。它既支持先进先出(FIFO)的队列模式,也支持后进先出(LIFO)的栈模式,是Java集合框架中功能最灵活的数据结构之一。本文将深入探讨Java中双向队列的核心操作、实现类及其典型应用场景。

阅读本文前如果你对队列不理解,请阅读本人的另外一篇文章!

深入理解Java中的队列:核心操作、实现与应用-CSDN博客


一、双向队列的核心操作

Java通过java.util.Deque接口定义了双向队列的操作方法,其核心方法分为头部操作尾部操作两类,且每种操作均提供“抛出异常”和“返回特殊值”两种形式:

操作类型头部操作(抛出异常)头部操作(返回特殊值)尾部操作(抛出异常)尾部操作(返回特殊值)描述
插入元素addFirst(e)offerFirst(e)addLast(e)offerLast(e)在头/尾部插入元素,失败时抛出异常或返回false
移除元素removeFirst()pollFirst()removeLast()pollLast()移除头/尾部元素,队列空时抛出异常或返回null
查看元素getFirst()peekFirst()getLast()peekLast()获取但不移除头/尾部元素,空队列时抛出异常或返回null

示例代码:

Deque<String> deque = new ArrayDeque<>();
deque.offerFirst("A");  // 头部插入"A"
deque.offerLast("B");   // 尾部插入"B"
String first = deque.pollFirst();  // 移除并返回"A"
String last = deque.peekLast();    // 查看"B"(不移除)

二、Java双向队列的常见实现类
  1. ArrayDeque

    • 底层结构:基于动态扩展的循环数组实现,内存紧凑,访问高效。

    • 特点

      • 默认初始容量为16,可自动扩容。

      • 插入/删除操作的时间复杂度为O(1)

      • 非线程安全,性能优于LinkedList

    • 适用场景:高频次的两端操作(如栈模拟、缓存)。

  2. LinkedList

    • 底层结构:基于双向链表实现,天然支持双向操作。

    • 特点

      • 插入/删除元素时无需移动其他元素,适合频繁增删的场景。

      • 支持索引访问(但效率低,时间复杂度为O(n))。

      • 非线程安全。

    • 适用场景:需要同时作为列表和双向队列使用的场景。

  3. ConcurrentLinkedDeque

    • 底层结构:基于无锁算法的并发双向链表。

    • 特点

      • 线程安全,适用于高并发环境。

      • 无界队列,支持非阻塞操作。

    • 适用场景:多线程任务调度、消息传递。

  4. LinkedBlockingDeque

    • 底层结构:基于链表的阻塞双向队列。

    • 特点

      • 可设置容量上限(有界队列)。

      • 提供阻塞式的插入/删除方法(如putFirst()takeLast())。

    • 适用场景:生产者-消费者模型,需双向阻塞操作的场景。


三、双向队列的典型应用场景
  1. 实现栈(Stack)
    Java官方推荐使用Deque替代传统的Stack类,因为Deque提供了更高效的栈操作:

    Deque<Integer> stack = new ArrayDeque<>();
    stack.push(1);      // 入栈
    stack.push(2);
    int top = stack.pop();  // 出栈(返回2)

  2. 滑动窗口算法
    在解决数组/字符串的子区间问题时,双向队列可高效维护窗口内的极值:

    // 求滑动窗口最大值(LeetCode 239)
    Deque<Integer> deque = new ArrayDeque<>();
    for (int i = 0; i < nums.length; i++) {
        while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
            deque.pollLast();  // 移除尾部较小的元素索引
        }
        deque.offerLast(i);
        // 移除超出窗口头部的索引
        if (deque.peekFirst() == i - k) {
            deque.pollFirst();
        }
        // 记录当前窗口最大值
        if (i >= k - 1) {
            result[i - k + 1] = nums[deque.peekFirst()];
        }
    }

  3. LRU缓存淘汰算法
    双向队列结合哈希表可高效实现LRU(最近最少使用)缓存策略:

    class LRUCache {
        private Deque<Integer> deque;  // 维护访问顺序
        private Map<Integer, Integer> map;
        private int capacity;
    
        public void refer(int key) {
            if (!map.containsKey(key)) {
                if (deque.size() == capacity) {
                    int last = deque.removeLast();  // 淘汰最久未使用的元素
                    map.remove(last);
                }
            } else {
                deque.remove(key);  // 移除旧位置
            }
            deque.offerFirst(key);  // 更新为最近访问
        }
    }

  4. 回文检测
    双向队列可快速判断字符串是否为回文:

    Deque<Character> deque = new ArrayDeque<>();
    for (char c : str.toCharArray()) {
        deque.addLast(c);
    }
    boolean isPalindrome = true;
    while (deque.size() > 1) {
        if (!deque.pollFirst().equals(deque.pollLast())) {
            isPalindrome = false;
            break;
        }
    }

  5. 多线程任务窃取(Work Stealing)
    在Fork/Join框架中,ConcurrentLinkedDeque允许工作线程从其他线程的队列尾部窃取任务,实现负载均衡。


四、如何选择双向队列的实现类?
场景需求推荐实现类理由
高频次两端操作(单线程)ArrayDeque内存连续,性能最优
需要链表特性(如索引访问)LinkedList支持列表操作,但两端操作性能略低于ArrayDeque
高并发环境ConcurrentLinkedDeque无锁并发,非阻塞操作
阻塞式双向队列LinkedBlockingDeque支持容量限制和阻塞等待

五、双向队列 vs 普通队列 vs 栈
特性双向队列(Deque)普通队列(Queue)栈(Stack)
插入/删除端头部和尾部尾部插入,头部删除仅顶部操作(LIFO)
灵活性最高(支持队列+栈操作)仅支持FIFO仅支持LIFO
典型实现ArrayDeque, LinkedListLinkedList, ArrayDequeDeque(推荐替代Stack)

六、总结

双向队列(Deque)凭借其两端操作的高效性,成为Java中解决复杂问题的利器。无论是实现栈、优化算法性能(如滑动窗口),还是设计高并发系统,双向队列都能提供简洁而强大的支持。开发者应根据具体场景选择ArrayDeque(性能优先)、LinkedList(功能多样)或并发实现类,充分发挥其灵活性和高效性。

扩展思考

  • 如何用Deque实现一个线程安全的阻塞栈?

  • 探索Deque在图形搜索算法(如BFS的变种)中的应用。

  • 对比DequeQueue在资源池管理中的优劣。

如果对你有帮助,请帮忙点个赞! 

相关文章:

  • Django 开发服务器
  • n8n AI工作流平台使用教程
  • #MES系统中的一些相关的名词
  • Linux命令-vim编辑
  • 2025年Q1 AI 学习应用总结
  • 8.8.1 简易计算器
  • css一些注意事项
  • 【linux】使用LNMP环境+Discuz论坛源程序
  • Excel处理控件Aspose.Cells指南:使用 Python 删除 Excel 中的重复行
  • Web Worker 中的 DedicatedWorkerGlobalScope 对象
  • LeetCode hot 100—搜索二维矩阵
  • 单片机 + 图像处理芯片 + TFT彩屏 触摸开关控件 v1.2
  • C语言核心结构+难点精讲+工程技巧
  • LLM - Dify 平台介绍
  • linux多线(进)程编程——番外1:内存映射与mmap
  • Java万级并发场景-实战解决
  • AI大模型原理可视化工具:深入浅出理解大语言模型的工作原理
  • 机器学习02——RNN
  • 【2025年五一数学建模竞赛A题】完整思路和代码
  • 代码随想录动态规划part02
  • 辽宁省委书记郝鹏、省长王新伟赶到辽阳火灾事故现场指导善后处置工作
  • 中国航天员乘组完成在轨交接,神十九乘组将于29日返回地球
  • 美国政府将暂时恢复部分受影响留学生的合法身份,并将制订新标准
  • 新城市志|中国消费第一城,迎来“补贴力度最大”购物节
  • 上海发布一组人事任免信息:钱晓、翁轶丛任市数据局副局长
  • 珠海市香洲区原区长刘齐英落马,此前已被终止省人大代表资格