java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java中Queue以及Deque

Java中Queue以及Deque用法示例详解

作者:xzkyd outpaper

在Java集合框架中Queue和Deque接口是两种重要的数据结构,它们用于存储和管理元素序列,这篇文章主要介绍了Java中Queue以及Deque用法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、核心概念与继承体系

二、Queue 核心方法与实现

1. 核心操作:

方法说明异常处理
offer(e)添加元素(推荐)失败返回false
add(e)添加元素失败抛IllegalStateException
poll()移除并返回队头元素空队列返回null
remove()移除并返回队头元素空队列抛NoSuchElementException
peek()查看队头元素(不删除)空队列返回null
element()查看队头元素(不删除)空队列抛NoSuchElementException

2. 常用实现类:

三、Deque 双端队列扩展

1. 核心操作增强:

// 头部操作
offerFirst(e)  // 头部插入
pollFirst()    // 头部移除
peekFirst()    // 查看头部

// 尾部操作
offerLast(e)   // 尾部插入(等价于offer)
pollLast()     // 尾部移除
peekLast()     // 查看尾部

// 栈操作
push(e)        // = offerFirst(e)
pop()          // = removeFirst()

2. 作为队列使用(FIFO)的API:

// 队列操作(FIFO:先进先出)
offerLast(e) 或 offer(e)  // 入队(尾部添加)
pollFirst() 或 poll()     // 出队(头部移除)
peekFirst() 或 peek()     // 查看队头

3. 作为栈使用(LIFO)的API:

// 栈操作(LIFO:后进先出)
push(e)         // 入栈 = addFirst(e)
pop()           // 出栈 = removeFirst()
peekFirst()     // 查看栈顶

4. API使用对照表:

操作队列模式(FIFO)栈模式(LIFO)等效方法
添加元素offerLast(e) / offer(e)push(e)addFirst(e)(栈)
addLast(e)(队列)
移除元素pollFirst() / poll()pop()removeFirst()
查看元素peekFirst() / peek()peekFirst()getFirst()

5. 代码示例:

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

// 作为队列使用(FIFO)
deque.offerLast("A"); // 队尾添加
deque.offerLast("B");
System.out.println(deque.pollFirst()); // A(队头移除)

// 作为栈使用(LIFO)
deque.push("C");      // 入栈
deque.push("D");
System.out.println(deque.pop());      // D(出栈)

// 混合操作(不推荐但可能)
deque.offerLast("E"); // 队尾添加(队列操作)
deque.push("F");      // 栈顶添加(栈操作)
System.out.println(deque.pollFirst()); // F(混合操作结果)

6. 常用实现类:

四、与其他集合类对比

特性Queue/DequeListSetMap
数据结构线性序列线性序列哈希表/树键值对
元素顺序FIFO/LIFO/优先级插入顺序/索引无序/排序无序/键排序
重复元素允许允许不允许值允许,键不允许
空值支持部分实现支持允许HashSet允许HashMap允许值
访问方式端点访问索引/迭代器迭代器键访问
典型实现ArrayDeque, PriorityQueueArrayList, LinkedListHashSet, TreeSetHashMap, TreeMap

五、使用场景与最佳实践

1. 队列场景:

2. 双端队列场景:

3. 选择指南:

六、常见问题

Q1:Queue和Deque的主要区别是什么?

A:

  1. 功能定位

    • Queue 是标准FIFO队列(尾部添加,头部移除)

    • Deque 是双端队列,扩展了Queue,支持两端操作

  2. 操作能力

    • Queue 只有队头出队(poll)、队尾入队(offer)

    • Deque 增加offerFirst/pollFirst等双端操作方法

  3. 栈功能

    • Deque 可直接作为栈使用(push/pop方法)

    • Queue 没有原生栈操作支持

Q2:ArrayDeque和LinkedList如何选择?

A:

  • ArrayDeque

    • 基于循环数组,内存连续

    • 两端操作时间复杂度O(1)

    • 随机访问更快,CPU缓存友好

    • 推荐场景:大多数队列/栈需求(默认选择)

  • LinkedList

    • 基于双向链表,内存分散

    • 支持List接口的索引访问

    • 插入删除中间元素更高效

    • 推荐场景

      • 需要同时使用队列和列表功能

      • 需要频繁在中间位置插入/删除

Q3:阻塞队列是什么?常用实现有哪些?

A:

  • 阻塞队列:当队列满时阻塞生产者,队列空时阻塞消费者(BlockingQueue接口)

  • 常用实现

    • ArrayBlockingQueue:数组实现的有界队列

    • LinkedBlockingQueue:链表实现的可选有界队列

    • PriorityBlockingQueue:带优先级的无界阻塞队列

    • SynchronousQueue:不存储元素的直接传递队列

Q4:Deque如何替代Stack?

A:

  1. Java官方推荐用Deque替代Stack

  2. 转换方式:

    Deque<Integer> stack = new ArrayDeque<>();
    stack.push(1);          // 入栈 = addFirst()
    int top = stack.peek(); // 查看栈顶 = peekFirst()
    int pop = stack.pop();  // 出栈 = removeFirst()
  3. 优势

    • 避免Stack的同步开销(Vector实现)

    • 更统一的集合API

    • 更好的性能(特别是ArrayDeque

Q5:PriorityQueue的排序原理?

A:

  • 基于堆数据结构(默认最小堆)

  • 排序规则:

    • 自然排序:元素实现Comparable

    • 定制排序:构造时传入Comparator

  • 特点:

    • 队头总是当前最值元素

    • 入队/出队时间复杂度O(log n)

    • 不支持null元素

Q6:如何使用Deque同时作为队列和栈?

A:
Deque可以同时支持队列和栈操作,但必须避免混用API

  1. 队列模式(FIFO):固定使用尾部添加+头部移除组合

// 推荐API组合
deque.offer(e);      // 入队(尾部)
String item = deque.poll(); // 出队(头部)
  1. 栈模式(LIFO):固定使用头部添加+头部移除组合

// 推荐API组合
deque.push(e);       // 入栈(头部)
String top = deque.pop();  // 出栈(头部)
  1. 危险操作:混用API会导致数据顺序混乱

// 错误示例(导致数据顺序不可预测)
deque.push("A");  // 栈操作(头部插入)
deque.offer("B"); // 队列操作(尾部插入)
// 此时队列:A<-B,但栈顶是A

Q7:为什么Java推荐用Deque代替Stack类?

A:
除了之前提到的性能优势,API设计也更合理:

  1. Stack的缺陷API

    // 老式Stack API(继承自Vector)
    stack.addElement(e);  // 非标准方法名
    stack.insertElementAt(e, 0); // 危险的低效操作
  2. Deque的标准栈API

    deque.push(e);  // 标准栈操作
    deque.pop();    // 直观的LIFO语义
    deque.peek();   // 查看栈顶
  3. 额外优势:Deque的栈操作时间复杂度均为O(1),而Stack的insertElementAt(0)是O(n)

七、高频面试进阶问题

  1. poll()和remove()有什么区别?

    • 行为相同:移除并返回队头元素

    • 空队列时:poll()返回nullremove()抛异常

  2. ArrayDeque初始容量是多少?如何扩容?

    • 默认初始容量16

    • 扩容规则:加倍容量(16→32→64...)

    • 重要特性:容量总是2的幂(位运算优化)

  3. 阻塞队列的put()和offer()区别?

    // 阻塞方法(无限等待)
    void put(E e) throws InterruptedException;
    
    // 非阻塞方法
    boolean offer(E e, long timeout, TimeUnit unit); // 限时等待
    boolean offer(E e);                              // 立即返回
  4. 为什么LinkedList实现了List和Deque?

    • 设计上支持多种访问方式:

      • 列表功能:索引访问/中间插入

      • 队列功能:FIFO操作

      • 双端功能:两端高效操作

    • 体现了接口隔离原则

总结 

到此这篇关于Java中Queue以及Deque用法的文章就介绍到这了,更多相关Java中Queue以及Deque内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文