优先级队列(堆)- 完整学习指南
📊 知识体系总览
mindmap
root((优先级队列(堆)))
核心概念
基本定义
带优先级的数据结构
优先级高先出队列
应用场景
游戏来电处理
成绩好先挑座位
系统任务调度
与普通队列对比
普通队列:FIFO
优先级队列:按优先级
实现差异
时间复杂度
数学性质
完全二叉树特性
大根堆/小根堆
堆序性质
堆的实现
存储方式
顺序存储(数组)
完全二叉树存储
节点索引关系
核心操作
向下调整(shiftDown)
应用场景
时间复杂度O(logn)
实现细节
边界条件
向上调整(shiftUp)
应用场景
时间复杂度O(logn)
实现细节
边界条件
建堆操作
自底向上建堆
时间复杂度O(n)
数学证明
代码实现
堆的插入删除
插入元素
尾端插入
向上调整
扩容机制
删除元素
删除堆顶
尾元素交换
向下调整
获取堆顶
数组第一个
不删除元素
优先级队列实现
封装堆结构
接口设计
扩容策略
线程安全性
PriorityQueue使用
基本特性
默认小根堆
自动扩容
不允许null
可比较元素
构造方法
默认构造
指定容量
集合构造
比较器构造
常用操作
插入(offer)
删除(poll)
查看(peek)
清空(clear)
大小(size)
扩容机制
小于64:2倍扩容
大于64:1.5倍
最大容量限制
比较器使用
自定义排序
大根堆实现
复杂对象排序
多条件比较
堆的应用
优先级队列
任务调度
事件处理
资源分配
堆排序
建堆操作
排序过程
时间复杂度
稳定性分析
与快排对比
Top-K问题
最大K个元素
最小K个元素
海量数据处理
内存优化
实时更新
中位数查找
双堆结构
实时中位数
流数据处理
定时任务
定时器实现
时间轮算法
延迟队列
性能分析
时间复杂度
插入:O(logn)
删除:O(logn)
建堆:O(n)
获取堆顶:O(1)
空间复杂度
数组存储:O(n)
堆高度:O(logn)
适用场景
频繁插入删除
需要优先级
内存有限
实时性要求
不适用场景
随机访问
范围查询
排序完全数组
频繁查找
1. 优先级队列核心概念
1.1 优先级队列基本概念
graph TD
A[优先级队列 Priority Queue] --> B[核心特性]
A --> C[与普通队列对比]
A --> D[应用场景]
A --> E[实现方式]
B --> B1[元素带优先级]
B --> B2[高优先级先出]
B --> B3[动态插入]
B --> B4[高效获取]
C --> C1[普通队列:FIFO]
C --> C2[优先级队列:按优先级]
C --> C3[操作复杂度不同]
C --> C4[底层实现差异]
D --> D1[任务调度]
D --> D2[事件处理]
D --> D3[游戏开发]
D --> D4[操作系统]
D --> D5[网络路由]
E --> E1[堆实现]
E --> E2[平衡二叉搜索树]
E --> E3[斐波那契堆]
E --> E4[二项堆]
B1 --> B11[优先级可比较]
B1 --> B12[自然排序]
B1 --> B13[自定义排序]
D1 --> D11[CPU调度]
D1 --> D12[线程池]
D1 --> D13[定时任务]
D2 --> D21[消息队列]
D2 --> D22[事件驱动]
D2 --> D23[实时系统]
概念详解:
优先级队列是一种特殊的队列,其中的每个元素都有一个"优先级"。与普通队列的FIFO规则不同,优先级队列总是让优先级最高的元素先出队。
核心特性:
-
动态优先级:可以随时插入新的带优先级元素
-
高效获取:可以在O(1)时间内获取最高优先级元素
-
灵活删除:可以在O(logn)时间内删除最高优先级元素
-
顺序维护:自动维护元素的优先级顺序
示例应用:
// 医院急诊系统示例
class EmergencySystem {
static class Patient {
String name;
int severity; // 1-5, 5为最严重
long arrivalTime;
public Patient(String name, int severity) {
this.name = name;
this.severity = severity;
this.arrivalTime = System.currentTimeMillis();
}
}
// 自定义比较器:先按紧急程度,再按到达时间
static class PatientComparator implements java.util.Comparator<Patient> {
@Override
public int compare(Patient p1, Patient p2) {
// 紧急程度高的先处理
if (p1.severity != p2.severity) {
return p2.severity - p1.severity; // 降序
}
// 紧急程度相同,先到的先处理
return Long.compare(p1.arrivalTime, p2.arrivalTime);
}
}
public static void main(String[] args) {
// 使用优先级队列实现急诊排队
java.util.PriorityQueue<Patient> emergencyQueue =
new java.util.PriorityQueue<>(new PatientComparator());
// 添加病人
emergencyQueue.offer(new Patient("张三", 3)); // 普通
emergencyQueue.offer(new Patient("李四", 5)); // 紧急
emergencyQueue.offer(new Patient("王五", 2)); // 轻微
emergencyQueue.offer(new Patient("赵六", 5)); // 紧急
// 处理病人
while (!emergencyQueue.isEmpty()) {
Patient patient = emergencyQueue.poll();
System.out.println("正在处理: " + patient.name +
" (紧急程度: " + patient.severity + ")");
}
}
}
与普通队列对比:
| 特性 | 普通队列 | 优先级队列 |
|---|---|---|
| 出队顺序 | FIFO | 按优先级 |
| 实现复杂度 | 简单 | 相对复杂 |
| 插入时间复杂度 | O(1) | O(logn) |
| 删除时间复杂度 | O(1) | O(logn) |
| 获取队首 | O(1) | O(1) |
| 典型实现 | 链表/数组 | 堆/平衡树 |
// 对比示例
class QueueComparison {
public static void main(String[] args) {
System.out.println("=== 普通队列 vs 优先级队列 ===");
// 1. 普通队列(FIFO)
System.out.println("\n1. 普通队列示例:");
java.util.Queue<Integer> normalQueue = new java.util.LinkedList<>();
normalQueue.offer(3);
normalQueue.offer(1);
normalQueue.offer(4);
normalQueue.offer(2);
System.out.print("出队顺序: ");
while (!normalQueue.isEmpty()) {
System.out.print(normalQueue.poll() + " "); // 3 1 4 2
}
// 2. 优先级队列(按值排序)
System.out.println("\n\n2. 优先级队列示例:");
java.util.PriorityQueue<Integer> priorityQueue = new java.util.PriorityQueue<>();
priorityQueue.offer(3);
priorityQueue.offer(1);
priorityQueue.offer(4);
priorityQueue.offer(2);
System.out.print("出队顺序: ");
while (!priorityQueue.isEmpty()) {
System.out.print(priorityQueue.poll() + " "); // 1 2 3 4
}
}
}
2. 堆的实现
2.1 堆的基本概念
graph TD
A[堆 Heap] --> B[核心定义]
A --> C[堆的分类]
A --> D[堆的性质]
A --> E[存储方式]
B --> B1[完全二叉树]
B --> B2[堆序性质]
B --> B3[数组存储]
B --> B4[高效操作]
C --> C1[大根堆]
C --> C2[小根堆]
C --> C3[二叉堆]
C --> C4[斐波那契堆]
D --> D1[结构性]
D --> D2[堆序性]
D --> D3[数学关系]
D --> D4[操作复杂度]
E --> E1[顺序存储]
E --> E2[索引计算]
E --> E3[空间效率]
E --> E4[完全二叉树]
C1 --> C11[父节点 ≥ 子节点]
C1 --> C12[根节点最大]
C1 --> C13[降序应用]
C2 --> C21[父节点 ≤ 子节点]
C2 --> C22[根节点最小]
C2 --> C23[升序应用]
D3 --> D31[节点索引关系]
D3 --> D32[高度公式]
D3 --> D33[节点数范围]
D3 --> D34[叶子节点数]
堆的定义:
堆是一种特殊的完全二叉树,满足堆序性质:
-
大根堆:每个节点的值都大于或等于其子节点的值
-
小根堆:每个节点的值都小于或等于其子节点的值
堆的数学性质:
// 堆的数学性质验证
class HeapProperties {
// 完全二叉树索引关系
public static void indexRelations() {
System.out.println("=== 堆的索引关系(0-based)===");
System.out.println("对于节点 i:");
System.out.println("父节点索引: (i-1)/2");
System.out.println("左孩子索引: 2*i+1");
System.out.println("右孩子索引: 2*i+2");
// 验证示例
int[] indices = {0, 1, 2, 3, 4, 5, 6};
System.out.println("\n具体示例:");
for (int i : indices) {
int parent = (i - 1) / 2;
int left = 2 * i + 1;
int right = 2 * i + 2;
System.out.printf("i=%d: parent=%d, left=%d, right=%d%n",
i, parent, left, right);
}
}
// 计算堆高度
public static int heapHeight(int n) {
// 高度 = ⌈log₂(n+1)⌉
return (int) Math.ceil(Math.log(n + 1) / Math.log(2));
}
// 计算叶子节点数
public static int leafCount(int n) {
// 完全二叉树叶子数 = ⌈n/2⌉
return (n + 1) / 2;
}
// 验证堆性质
public static boolean isMaxHeap(int[] heap, int n) {
for (int i = 0; i < n; i++) {
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && heap[i] < heap[left]) {
return false;
}
if (right < n && heap[i] < heap[right]) {
return false;
}
}
return true;
}
public static boolean isMinHeap(int[] heap, int n) {
for (int i = 0; i < n; i++) {
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && heap[i] > heap[left]) {
return false;
}
if (right < n && heap[i] > heap[right]) {
return false;
}
}
return true;
}
public static void main(String[] args) {
indexRelations();
System.out.println("\n=== 堆的数学性质 ===");
int[] sizes = {1, 3, 7, 10, 15, 31};
for (int n : sizes) {
System.out.printf("节点数: %d, 高度: %d, 叶子数: %d%n",
n, heapHeight(n), leafCount(n));
}
// 测试堆验证
int[] maxHeap = {9, 8, 7, 6, 5, 4, 3};
int[] minHeap = {1, 2, 3, 4, 5, 6, 7};
int[] notHeap = {1, 9, 2, 8, 3, 7, 4};
System.out.println("\n=== 堆验证测试 ===");
System.out.println("maxHeap是大根堆? " + isMaxHeap(maxHeap, maxHeap.length));
System.out.println("minHeap是小根堆? " + isMinHeap(minHeap, minHeap.length));
System.out.println("notHeap是大根堆? " + isMaxHeap(notHeap, notHeap.length));
System.out.println("notHeap是小根堆? " + isMinHeap(notHeap, notHeap.length));
}
}
选择题解答:
public class HeapQuiz {
public static void main(String[] args) {
System.out.println("=== 堆相关选择题解答 ===");
// 1. 下列关键字序列为堆的是:
int[][] options = {
{100, 60, 70, 50, 32, 65}, // A
{60, 70, 65, 50, 32, 100}, // B
{65, 100, 70, 32, 50, 60}, // C
{70, 65, 100, 32, 50, 60}, // D
{32, 50, 100, 70, 65, 60}, // E
{50, 100, 70, 65, 60, 32} // F
};
System.out.println("\n1. 判断哪些是大根堆:");
for (int i = 0; i < options.length; i++) {
boolean isMaxHeap = true;
for (int j = 0; j < options[i].length; j++) {
int left = 2 * j + 1;
int right = 2 * j + 2;
if (left < options[i].length && options[i][j] < options[i][left]) {
isMaxHeap = false;
break;
}
if (right < options[i].length && options[i][j] < options[i][right]) {
isMaxHeap = false;
break;
}
}
char option = (char)('A' + i);
System.out.printf("%c: %s -> %s%n", option,
java.util.Arrays.toString(options[i]),
isMaxHeap ? "是大根堆" : "不是大根堆");
}
System.out.println("答案: A (选A)");
// 2. 已知小根堆为8,15,10,21,34,16,12,删除关键字8之后的重建
System.out.println("\n2. 删除堆顶元素的重建过程:");
int[] minHeap = {8, 15, 10, 21, 34, 16, 12};
System.out.println("原始小根堆: " + java.util.Arrays.toString(minHeap));
System.out.println("删除8后,用最后一个元素12替换堆顶");
System.out.println("然后从堆顶开始向下调整");
System.out.println("比较过程: 12与15、10比较,与10交换");
System.out.println(" 12与16比较,不需要交换");
System.out.println("总共比较次数: 3次 (选C)");
// 4. 最小堆删除堆顶元素
System.out.println("\n4. 最小堆删除堆顶元素:");
int[] heap = {0, 3, 2, 5, 7, 4, 6, 8};
System.out.println("原始堆: " + java.util.Arrays.toString(heap));
System.out.println("删除0后,用8替换堆顶");
System.out.println("向下调整过程: 8与3、2比较,与2交换");
System.out.println(" 8与4、6比较,与4交换");
System.out.println(" 8与7、?比较,不需要交换");
System.out.println("最终结果: [2, 3, 4, 5, 7, 8, 6] (选C)");
}
}
2.2 堆的核心操作实现
// 完整的堆实现
class MyHeap {
private int[] heap;
private int size;
private int capacity;
private boolean isMaxHeap; // true为大根堆,false为小根堆
// 构造方法
public MyHeap(int capacity, boolean isMaxHeap) {
this.capacity = capacity;
this.size = 0;
this.isMaxHeap = isMaxHeap;
this.heap = new int[capacity];
}
public MyHeap(int[] array, boolean isMaxHeap) {
this.capacity = array.length;
this.size = array.length;
this.isMaxHeap = isMaxHeap;
this.heap = array.clone();
buildHeap();
}
// 核心操作1: 向下调整
public void shiftDown(int parent) {
int child = 2 * parent + 1; // 左孩子
while (child < size) {
// 找到左右孩子中更大(小)的那个
if (child + 1 < size &&
((isMaxHeap && heap[child] < heap[child + 1]) ||
(!isMaxHeap && heap[child] > heap[child + 1]))) {
child++; // 指向右孩子
}
// 判断是否需要交换
boolean needSwap = (isMaxHeap && heap[parent] < heap[child]) ||
(!isMaxHeap && heap[parent] > heap[child]);
if (!needSwap) {
break; // 已经满足堆性质
}
// 交换父子节点
swap(parent, child);
// 继续向下调整
parent = child;
child = 2 * parent + 1;
}
}
// 核心操作2: 向上调整
public void shiftUp(int child) {
int parent = (child - 1) / 2;
while (child > 0) {
boolean needSwap = (isMaxHeap && heap[parent] < heap[child]) ||
(!isMaxHeap && heap[parent] > heap[child]);
if (!needSwap) {
break; // 已经满足堆性质
}
// 交换父子节点
swap(parent, child);
// 继续向上调整
child = parent;
parent = (child - 1) / 2;
}
}
// 核心操作3: 建堆
private void buildHeap() {
// 从最后一个非叶子节点开始向下调整
for (int i = (size - 2) / 2; i >= 0; i--) {
shiftDown(i);
}
}
// 插入元素
public boolean offer(int value) {
if (size >= capacity) {
// 扩容
capacity = capacity < 64 ? capacity * 2 : capacity + capacity / 2;
heap = java.util.Arrays.copyOf(heap, capacity);
}
heap[size] = value;
shiftUp(size);
size++;
return true;
}
// 删除堆顶元素
public int poll() {
if (size == 0) {
throw new IllegalStateException("堆为空");
}
int result = heap[0];
heap[0] = heap[size - 1];
size--;
if (size > 0) {
shiftDown(0);
}
return result;
}
// 获取堆顶元素
public int peek() {
if (size == 0) {
throw new IllegalStateException("堆为空");
}
return heap[0];
}
// 堆排序
public void heapSort() {
int originalSize = size;
// 建堆
buildHeap();
// 排序
for (int i = size - 1; i > 0; i--) {
swap(0, i);
size--;
shiftDown(0);
}
size = originalSize;
// 如果原来是大根堆,排序后是升序,需要反转
if (isMaxHeap) {
reverse();
}
}
// 辅助方法
private void swap(int i, int j) {
int temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
private void reverse() {
for (int i = 0; i < size / 2; i++) {
swap(i, size - 1 - i);
}
}
// 工具方法
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void clear() {
size = 0;
}
public int[] toArray() {
return java.util.Arrays.copyOf(heap, size);
}
@Override
public String toString() {
return java.util.Arrays.toString(toArray());
}
// 测试代码
public static void main(String[] args) {
System.out.println("=== 堆的完整实现测试 ===");
// 1. 测试大根堆
System.out.println("\n1. 大根堆测试:");
MyHeap maxHeap = new MyHeap(10, true);
int[] testData = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
for (int num : testData) {
maxHeap.offer(num);
System.out.println("插入 " + num + " 后: " + maxHeap);
}
System.out.println("堆排序前: " + maxHeap);
maxHeap.heapSort();
System.out.println("堆排序后: " + maxHeap);
// 2. 测试小根堆
System.out.println("\n2. 小根堆测试:");
MyHeap minHeap = new MyHeap(testData, false);
System.out.println("建堆结果: " + minHeap);
System.out.print("依次弹出: ");
while (!minHeap.isEmpty()) {
System.out.print(minHeap.poll() + " ");
}
// 3. 测试向下调整
System.out.println("\n\n3. 向下调整测试:");
int[] arr = {9, 8, 7, 6, 5, 4, 3};
MyHeap testHeap = new MyHeap(arr, true);
System.out.println("原始数组: " + java.util.Arrays.toString(arr));
System.out.println("建堆结果: " + testHeap);
// 4. 测试向上调整
System.out.println("\n4. 向上调整测试:");
MyHeap upTest = new MyHeap(10, false);
for (int i = 10; i >= 1; i--) {
upTest.offer(i);
}
System.out.println("倒序插入1-10的结果: " + upTest);
}
}
堆操作的时间复杂度分析:
| 操作 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 向下调整 | O(log n) | O(1) | 最坏从根到叶 |
| 向上调整 | O(log n) | O(1) | 最坏从叶到根 |
| 建堆 | O(n) | O(1) | 数学证明 |
| 插入 | O(log n) | O(1) | 尾部插入+向上调整 |
| 删除 | O(log n) | O(1) | 交换+向下调整 |
| 获取堆顶 | O(1) | O(1) | 数组第一个元素 |
| 堆排序 | O(n log n) | O(1) | 原地排序 |
建堆时间复杂度证明:
// 建堆时间复杂度分析
class HeapTimeComplexity {
public static void main(String[] args) {
System.out.println("=== 建堆时间复杂度分析 ===");
// 建堆过程:从最后一个非叶子节点开始向下调整
// 节点i需要调整的高度为h-i
// 总比较次数 = Σ(i=0 to h-1) 2^i * (h-i)
int h = 5; // 树高度
int totalNodes = (1 << h) - 1; // 2^h - 1
System.out.println("树高度: " + h);
System.out.println("总节点数: " + totalNodes);
// 计算各层调整次数
int totalComparisons = 0;
System.out.println("\n各层调整分析:");
for (int i = h - 1; i >= 0; i--) {
int nodesAtLevel = 1 << (h - 1 - i); // 2^(h-1-i)
int comparisonsPerNode = i; // 调整高度
int levelComparisons = nodesAtLevel * comparisonsPerNode;
totalComparisons += levelComparisons;
System.out.printf("第%d层: %d个节点 × %d次比较 = %d%n",
h - i, nodesAtLevel, comparisonsPerNode, levelComparisons);
}
System.out.println("总比较次数: " + totalComparisons);
System.out.println("数学证明: T(n) = O(n)");
// 实际测试
System.out.println("\n=== 实际性能测试 ===");
for (int n = 1000; n <= 1000000; n *= 10) {
int[] arr = new int[n];
java.util.Random rand = new java.util.Random();
for (int i = 0; i < n; i++) {
arr[i] = rand.nextInt(10000);
}
long start = System.nanoTime();
MyHeap heap = new MyHeap(arr, true);
long end = System.nanoTime();
System.out.printf("n=%d: 建堆时间=%.3fms%n",
n, (end - start) / 1e6);
}
}
}
3. PriorityQueue使用详解
3.1 PriorityQueue基本使用
// PriorityQueue完整示例
class PriorityQueueDemo {
// 1. 基本用法
public static void basicUsage() {
System.out.println("=== PriorityQueue基本用法 ===");
// 创建小根堆(默认)
java.util.PriorityQueue<Integer> minHeap = new java.util.PriorityQueue<>();
// 插入元素
minHeap.offer(5);
minHeap.offer(2);
minHeap.offer(8);
minHeap.offer(1);
minHeap.offer(3);
System.out.println("小根堆内容: " + minHeap);
System.out.print("出队顺序: ");
while (!minHeap.isEmpty()) {
System.out.print(minHeap.poll() + " ");
}
System.out.println();
}
// 2. 构造方法
public static void constructors() {
System.out.println("\n=== PriorityQueue构造方法 ===");
// 1) 默认构造
java.util.PriorityQueue<Integer> q1 = new java.util.PriorityQueue<>();
System.out.println("默认构造容量: 11");
// 2) 指定初始容量
java.util.PriorityQueue<Integer> q2 = new java.util.PriorityQueue<>(20);
System.out.println("指定容量20");
// 3) 从集合构造
java.util.List<Integer> list = java.util.Arrays.asList(9, 5, 7, 1, 3);
java.util.PriorityQueue<Integer> q3 = new java.util.PriorityQueue<>(list);
System.out.println("从列表构造: " + q3);
// 4) 从其他PriorityQueue构造
java.util.PriorityQueue<Integer> q4 = new java.util.PriorityQueue<>(q3);
System.out.println("从其他队列构造: " + q4);
}
// 3. 比较器使用
public static void comparators() {
System.out.println("\n=== 比较器使用 ===");
// 自定义比较器实现大根堆
java.util.Comparator<Integer> maxHeapComparator = new java.util.Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return b - a; // 降序
}
};
java.util.PriorityQueue<Integer> maxHeap =
new java.util.PriorityQueue<>(maxHeapComparator);
maxHeap.offer(5);
maxHeap.offer(2);
maxHeap.offer(8);
maxHeap.offer(1);
maxHeap.offer(3);
System.out.println("大根堆内容: " + maxHeap);
System.out.print("出队顺序: ");
while (!maxHeap.isEmpty()) {
System.out.print(maxHeap.poll() + " ");
}
System.out.println();
}
// 4. 复杂对象排序
public static void complexObjects() {
System.out.println("\n=== 复杂对象排序 ===");
class Student {
String name;
int score;
int age;
Student(String name, int score, int age) {
this.name = name;
this.score = score;
this.age = age;
}
@Override
public String toString() {
return name + "(" + score + ", " + age + ")";
}
}
// 按分数降序,分数相同按年龄升序
java.util.Comparator<Student> studentComparator = new java.util.Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
if (s1.score != s2.score) {
return s2.score - s1.score; // 分数降序
}
return s1.age - s2.age; // 年龄升序
}
};
java.util.PriorityQueue<Student> studentQueue =
new java.util.PriorityQueue<>(studentComparator);
studentQueue.offer(new Student("张三", 85, 20));
studentQueue.offer(new Student("李四", 92, 19));
studentQueue.offer(new Student("王五", 85, 21));
studentQueue.offer(new Student("赵六", 78, 20));
System.out.println("学生排名:");
while (!studentQueue.isEmpty()) {
System.out.println(studentQueue.poll());
}
}
// 5. 常用API
public static void apiUsage() {
System.out.println("\n=== 常用API ===");
java.util.PriorityQueue<Integer> pq = new java.util.PriorityQueue<>();
// 添加元素
System.out.println("添加元素:");
pq.offer(10);
pq.offer(30);
pq.offer(20);
System.out.println("添加后: " + pq);
System.out.println("大小: " + pq.size());
// 查看堆顶
System.out.println("堆顶元素: " + pq.peek());
// 删除堆顶
System.out.println("删除堆顶: " + pq.poll());
System.out.println("删除后: " + pq);
// 清空
pq.clear();
System.out.println("清空后大小: " + pq.size());
System.out.println("是否为空: " + pq.isEmpty());
}
// 6. 扩容机制
public static void expansion() {
System.out.println("\n=== 扩容机制 ===");
java.util.PriorityQueue<Integer> pq = new java.util.PriorityQueue<>(2);
System.out.println("初始容量: 2");
for (int i = 1; i <= 10; i++) {
pq.offer(i);
// 通过反射获取内部数组长度
try {
java.lang.reflect.Field field = pq.getClass().getDeclaredField("queue");
field.setAccessible(true);
Object[] array = (Object[]) field.get(pq);
System.out.println("插入" + i + "后,数组长度: " + array.length);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("\n扩容规则:");
System.out.println("1. 容量<64时: 2倍扩容");
System.out.println("2. 容量≥64时: 1.5倍扩容");
System.out.println("3. 最大容量: Integer.MAX_VALUE - 8");
}
public static void main(String[] args) {
basicUsage();
constructors();
comparators();
complexObjects();
apiUsage();
expansion();
}
}
3.2 常见错误和注意事项
// PriorityQueue常见错误
class PriorityQueueErrors {
public static void commonErrors() {
System.out.println("=== PriorityQueue常见错误 ===");
// 错误1: 插入null
try {
java.util.PriorityQueue<Integer> pq = new java.util.PriorityQueue<>();
pq.offer(null); // 抛出NullPointerException
} catch (NullPointerException e) {
System.out.println("错误1: 不能插入null - " + e.getMessage());
}
// 错误2: 插入不可比较对象
try {
class NotComparable {
int value;
NotComparable(int v) { value = v; }
}
java.util.PriorityQueue<NotComparable> pq =
new java.util.PriorityQueue<>();
pq.offer(new NotComparable(1)); // 抛出ClassCastException
} catch (ClassCastException e) {
System.out.println("错误2: 对象必须可比较 - " + e.getMessage());
}
// 错误3: 遍历时修改
try {
java.util.PriorityQueue<Integer> pq = new java.util.PriorityQueue<>();
pq.offer(1);
pq.offer(2);
pq.offer(3);
// 错误的遍历方式
for (Integer num : pq) {
if (num == 2) {
pq.remove(num); // 可能抛出ConcurrentModificationException
}
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("错误3: 遍历时不能修改 - " + e.getMessage());
}
// 错误4: 容量为0
try {
java.util.PriorityQueue<Integer> pq = new java.util.PriorityQueue<>(0);
} catch (IllegalArgumentException e) {
System.out.println("错误4: 初始容量必须≥1 - " + e.getMessage());
}
// 正确做法
System.out.println("\n=== 正确做法 ===");
// 1. 正确遍历
java.util.PriorityQueue<Integer> pq = new java.util.PriorityQueue<>();
pq.offer(1);
pq.offer(2);
pq.offer(3);
System.out.println