
在 Java 日常开发和算法刷题中ArrayDeque、LinkedList和PriorityQueue是三个出场率极高的容器。它们都实现了Queue接口但底层结构、支持的操作和适用场景却截然不同。本文将从方法 API、底层特性、横向对比到代码实战为你彻底梳理这三个集合类的核心知识。一、ArrayDeque —— 循环数组实现的双端队列官方推荐可用作 FIFO 队列、LIFO 栈、双端队列禁止存放null元素。ArrayDeque底层由循环数组实现头尾操作均摊时间复杂度均为O(1)性能优于LinkedList。它是Deque接口的主要实现类在需要队列或栈的场景中应优先选用。1.1 双端队列常用 API方法作用失败行为addFirst(e)头部添加元素容量满时抛异常addLast(e)/add(e)尾部添加元素容量满时抛异常offerFirst(e)头部添加元素返回true/falseofferLast(e)/offer(e)尾部添加元素返回true/falseremoveFirst()删除并返回头部元素空队列抛异常removeLast()删除并返回尾部元素空队列抛异常pollFirst()删除并返回头部元素空队列返回nullpollLast()删除并返回尾部元素空队列返回nullgetFirst()查看头部元素不删除空队列抛异常getLast()查看尾部元素不删除空队列抛异常peekFirst()查看头部元素不删除空队列返回nullpeekLast()查看尾部元素不删除空队列返回null1.2 作为栈使用官方推荐替代Stackpush(e)→ 等价于addFirst(e)—— 入栈pop()→ 等价于removeFirst()—— 出栈peek()→ 等价于peekFirst()—— 查看栈顶1.3 关键特性底层循环数组自动扩容头尾操作极快。不支持按索引随机访问没有get(index)方法。非线程安全多线程并发需自行同步。不允许存入null元素。1.4 代码示例import java.util.ArrayDeque;public class ArrayDequeDemo {public static void main(String[] args) {ArrayDequeInteger deque new ArrayDeque();// 1. 当作普通 FIFO 队列先进先出deque.offer(1); // 队尾入队deque.offer(2);Integer head deque.poll(); // 队头出队空返回 nullInteger peek deque.peek(); // 查看队头不删除// 2. 当作栈使用后进先出推荐替代 Stackdeque.push(10); // 入栈deque.push(20);Integer top deque.pop(); // 弹出栈顶空抛异常Integer stackTop deque.peek(); // 查看栈顶// 3. 双端队列头尾自由操作滑动窗口、单调队列核心deque.offerFirst(100); // 头部添加deque.offerLast(200); // 尾部添加deque.pollFirst(); // 头部删除deque.pollLast(); // 尾部删除}}适用场景BFS 队列、单调栈、滑动窗口单调队列、任何需要纯队列或栈的场合。二、LinkedList —— 双向链表一身三用允许存放null元素同时实现了List和Deque接口可用作列表、队列或双端队列。LinkedList底层为双向链表在头尾节点的增删同样是 O(1)但由于需要维护额外节点对象内存开销和缓存友好度均不如ArrayDeque。2.1 List 接口方法体现链表特性add(int index, E element)—— 指定位置插入get(int index)—— 按索引获取元素时间复杂度 O(n)remove(int index)—— 按索引删除⚠️ 由于get(i)需要遍历不适合大量随机访问。2.2 Deque / Queue 全套方法LinkedList实现了与ArrayDeque完全相同的方法签名addFirst、addLast、offerFirst、offerLast、removeFirst、pollFirst、peekFirst、push、pop、peek等等。2.3 优缺点✅ 优势在已经定位到节点的前提下中间插入/删除只涉及指针更改。❌ 劣势每个元素包装成Node对象内存占用大CPU 缓存不友好纯头尾操作性能弱于ArrayDeque。2.4 代码示例import java.util.LinkedList;public class LinkedListDemo {public static void main(String[] args) {LinkedListInteger list new LinkedList();// 1. 当作 List 使用支持索引但 O(n)list.add(1);list.add(1, 5); // 在索引 1 处插入int num list.get(0); // 随机访问// 2. 当作 FIFO 队列list.offer(10);list.poll();list.peek();// 3. 当作栈 / 双端队列方法同 ArrayDequelist.push(100);list.pop();list.offerFirst(20);list.pollLast();}}适用场景需要同时满足List 索引访问队列/栈操作或者频繁在链表中间位置增删元素的场景。三、PriorityQueue —— 优先级队列二叉堆实现仅实现Queue接口不是双端队列不允许null元素必须可比较默认最小堆。PriorityQueue底层基于数组实现的二叉堆入队offer和出队poll的时间复杂度均为O(log n)。它只能操作队首堆顶不能操作队尾。3.1 核心 Queue 方法方法功能offer(E e)加入元素自动上浮调整堆O(log n)poll()取出并移除堆顶元素优先级最高下沉调整O(log n)空返回nullpeek()查看堆顶元素O(1)空返回nulladd(E e)等价offer失败抛异常remove()等价poll空队列抛异常element()等价peek空队列抛异常3.2 重要坑点没有addFirst、pollLast这类双端方法直接迭代for-each不保证有序只有不断poll()才能按优先级顺序取出。删除任意元素remove(Object o)需要 O(n) 遍历查找。默认是最小堆构造大根堆需传入Comparator.reverseOrder()。3.3 代码示例import java.util.PriorityQueue;import java.util.Comparator;public class PriorityQueueDemo {public static void main(String[] args) {// 1. 默认最小堆堆顶是最小值PriorityQueueInteger minHeap new PriorityQueue();minHeap.offer(5);minHeap.offer(2);minHeap.offer(8);System.out.println(minHeap.peek()); // 输出 2minHeap.poll(); // 移除堆顶// 2. 最大堆写法PriorityQueueInteger maxHeap new PriorityQueue(Comparator.reverseOrder());maxHeap.offer(3);maxHeap.offer(9);System.out.println(maxHeap.peek()); // 输出 9// ❌ 错误没有 offerFirst 方法// maxHeap.offerFirst(1);}}适用场景TopK 问题、多路归并、任务优先级调度、动态数据流求中位数等。四、通用方法设计模式Queue 接口规范所有队列实现都遵循同一套两套方法约定记忆一组即可操作失败时抛异常失败时返回特殊值推荐插入add(e)offer(e)删除remove()poll()查看队首element()peek()五、横向关键对比维度ArrayDequeLinkedListPriorityQueue底层结构循环数组双向链表数组实现的二叉堆实现接口DequeListDequeQueue能否做栈 / 双端队列✅✅❌头尾增删O(1) 均摊最快O(1)但常数大—插入 / 删除——O(log n)是否允许null❌✅❌有序规则按插入顺序按插入顺序按优先级堆序随机索引访问❌✅ O(n)❌六、场景选择速记口诀滑动窗口、单调队列、普通栈与队列→ArrayDeque同时需要 List 索引访问和队列操作或频繁中间插入删除→LinkedList前 K 大/小、任务调度、多路归并→PriorityQueue七、总结Queue的设计十分灵活一个Queue接口背后却对应着多种截然不同的实现。理解它们的底层数据结构和性能边界是写出高效、优雅代码的基础。希望本文的 API 速查、代码示例和场景对比能帮助你快速选择适合的容器在开发与面试中游刃有余。