在 Java 中,PriorityQueue
(优先级队列)是一种基于优先级堆的队列实现,它能够保证每次取出的元素都是队列中优先级最高的元素(默认是自然排序的最小元素)。与普通队列的 "先进先出"(FIFO)不同,PriorityQueue
的元素顺序由其优先级决定。
Comparable
接口)Comparator
接口)PriorityBlockingQueue
NullPointerException
add(E e)
/offer(E e)
:添加元素(超出容量时,add 抛异常,offer 返回 false)poll()
:移除并返回优先级最高的元素(队列为空时返回 null)peek()
:返回但不移除优先级最高的元素(队列为空时返回 null)size()
:返回元素数量isEmpty()
:判断是否为空clear()
:清空队列import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
// 创建默认的优先级队列(小顶堆)
PriorityQueue pq = new PriorityQueue<>();
// 添加元素
pq.add(3);
pq.add(1);
pq.add(2);
// 输出元素(每次取出最小元素)
while (!pq.isEmpty()) {
System.out.println(pq.poll()); // 输出:1, 2, 3
}
}
}
import java.util.Comparator;
import java.util.PriorityQueue;
public class MaxHeapExample {
public static void main(String[] args) {
// 创建大顶堆(通过自定义比较器)
PriorityQueue maxHeap = new PriorityQueue<>(
new Comparator() {
@Override
public int compare(Integer a, Integer b) {
return b - a; // 降序排列
}
}
);
maxHeap.add(3);
maxHeap.add(1);
maxHeap.add(2);
while (!maxHeap.isEmpty()) {
System.out.println(maxHeap.poll()); // 输出:3, 2, 1
}
}
}
自定义对象
import java.util.PriorityQueue;
// 自定义对象需实现Comparable接口
class Student implements Comparable {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
// 按分数升序排列
@Override
public int compareTo(Student other) {
return this.score - other.score;
}
@Override
public String toString() {
return name + "(" + score + ")";
}
}
public class CustomObjectExample {
public static void main(String[] args) {
PriorityQueue students = new PriorityQueue<>();
students.add(new Student("Alice", 85));
students.add(new Student("Bob", 92));
students.add(new Student("Charlie", 78));
while (!students.isEmpty()) {
System.out.println(students.poll());
// 输出:Charlie(78), Alice(85), Bob(92)
}
}
}
PriorityQueue
的iterator()
方法不能保证按优先级顺序遍历元素poll()
方法)Comparable
接口或提供Comparator
,否则会抛出ClassCastException
iterator()
方法不能保证按优先级顺序遍历元素?PriorityQueue
底层使用二叉堆(默认是小顶堆)实现,堆的结构特点是:
例如,一个小顶堆的内部存储可能是这样的(逻辑结构):
1
/ \
3 2
/ \
4 5
其物理存储(数组)可能是 [1,3,2,4,5]
,显然数组本身并不是完全有序的。
当使用iterator()
遍历这个数组时,会按照[1,3,2,4,5]
的顺序访问,而非优先级顺序[1,2,3,4,5]
。
PriorityQueue
的核心目标是高效地获取和删除优先级最高的元素(poll()
/peek()
操作),这两个操作的时间复杂度是O(log n)
。
如果要保证iterator()
能按顺序遍历,有两种方案,但都会带来性能问题:
O(n)
时间来保持有序性poll()
等操作无法高效执行因此,Java 的设计者选择不保证迭代顺序,以维持PriorityQueue
在核心操作上的高效性。
如果需要按优先级顺序遍历元素,正确的做法是:
while (!pq.isEmpty()) {
System.out.println(pq.poll()); // 每次取出优先级最高的元素
}
但这种方式会清空队列。如果需要保留原队列,可先复制一份再遍历:
PriorityQueue copy = new PriorityQueue<>(original);
while (!copy.isEmpty()) {
System.out.println(copy.poll());
}