Queue详解
Java 中的队列(Queue)是一种数据结构,它遵循先进先出(FIFO)的原则。队列可以用于在一个集合中保存一组元素,并支持在队列的尾部添加元素,以及在队列的头部移除元素。
Java 标准库提供了 java.util.Queue
接口来表示队列,它是一个包含多个方法的接口。下面是一些常用的方法:
add(E element)
:将指定元素添加到队列的尾部。如果队列已满,则抛出异常。offer(E element)
:将指定元素添加到队列的尾部。如果队列已满,则返回 false。remove()
:从队列的头部删除并返回一个元素。如果队列为空,则抛出异常。poll()
:从队列的头部删除并返回一个元素。如果队列为空,则返回 null。element()
:获取队列的头部元素,但不删除它。如果队列为空,则抛出异常。peek()
:获取队列的头部元素,但不删除它。如果队列为空,则返回 null。
除了 java.util.Queue
接口之外,Java 还提供了一些具体的队列类,如 LinkedList
和 ArrayDeque
。这些类都实现了 java.util.Queue
接口,并且提供了自己的特定行为和性能特征。您可以根据您的应用程序需求来选择最适合的队列实现。
1.LinkedList实现
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
// 添加元素到队列尾部
queue.add("Alice");
queue.offer("Bob");
// 获取队列头部元素并删除
String head = queue.remove();
System.out.println("Head of the queue (after remove): " + head);
// 获取队列头部元素但不删除
head = queue.element();
System.out.println("Head of the queue (after element): " + head);
// 添加更多元素到队列尾部
queue.add("Charlie");
queue.offer("David");
// 遍历队列中的元素
for (String s : queue) {
System.out.println(s);
}
// 获取队列头部元素并删除
head = queue.poll();
System.out.println("Head of the queue (after poll): " + head);
// 获取队列头部元素但不删除
head = queue.peek();
System.out.println("Head of the queue (after peek): " + head);
}
}
输出结果:
Head of the queue (after remove): Alice
Head of the queue (after element): Bob
Bob
Charlie
David
Head of the queue (after poll): Bob
Head of the queue (after peek): Charlie
2.ArrayDeque实现
import java.util.ArrayDeque;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new ArrayDeque<>();
// 添加元素到队列尾部
queue.offer(10);
queue.add(20);
// 获取队列头部元素并删除
int head = queue.remove();
System.out.println("Head of the queue (after remove): " + head);
// 获取队列头部元素但不删除
head = queue.element();
System.out.println("Head of the queue (after element): " + head);
// 添加更多元素到队列尾部
queue.offer(30);
queue.add(40);
// 遍历队列中的元素
for (int num : queue) {
System.out.println(num);
}
// 获取队列头部元素并删除
head = queue.poll();
System.out.println("Head of the queue (after poll): " + head);
// 获取队列头部元素但不删除
head = queue.peek();
System.out.println("Head of the queue (after peek): " + head);
}
}
输出结果:
Head of the queue (after remove): 10
Head of the queue (after element): 20
20
30
40
Head of the queue (after poll): 20
Head of the queue (after peek): 30
3.使用场景差异(底层结构不同)
LinkedList 和 ArrayDeque 都实现了 java.util.Queue 接口,但它们在底层数据结构和特性上有一些区别。
LinkedList:
- 底层数据结构为双向链表,每个元素都包含前一个和后一个元素的引用。
- 支持对队列两端的操作,因此在头部和尾部都可以高效地进行元素的插入和删除操作。
- 链表的插入和删除操作的时间复杂度为 O(1)。
- 链表不支持随机访问,需要遍历整个链表才能访问指定位置的元素。
- 在使用迭代器遍历时,效率比较低。
ArrayDeque:
- 底层数据结构为循环数组,可以在数组的两端进行元素的插入和删除操作。
- 支持对队列两端的高效操作,因此在头部和尾部插入和删除元素的时间复杂度为 O(1)。
- 支持随机访问,可以通过索引直接访问指定位置的元素。
- 数组的大小会自动调整以适应元素的数量。
- 在使用迭代器遍历时,效率较高。
如果需要经常在队列两端进行元素的插入和删除操作,且随机访问不是主要需求,可以选择 LinkedList。
如果需要在队列两端进行高效的插入和删除操作,并且需要支持随机访问操作,可以选择 ArrayDeque。