0

0

Java中PriorityQueue的基础使用方法

P粉602998670

P粉602998670

发布时间:2025-09-22 18:00:02

|

795人浏览过

|

来源于php中文网

原创

PriorityQueue是Java中基于优先级出队的队列,默认为小顶堆,每次取出最小元素;其核心方法包括add/offer入队、poll出队、peek查看队首;与普通FIFO队列不同,它按元素优先级排序而非入队顺序;可通过实现Comparable接口或传入Comparator自定义排序规则;常用于Dijkstra算法、任务调度、Top K问题等需动态处理最高优先级元素的场景。

java中priorityqueue的基础使用方法

Java里的

PriorityQueue
,说白了,就是一种特殊的队列。它不像我们常说的先进先出(FIFO)队列那样,而是根据元素的优先级来决定谁先出队。默认情况下,它是一个小顶堆,这意味着每次你取元素,拿到的总是当前队列里最小的那个。这在很多需要“总是处理最紧急或最小/最大”元素的场景下,简直是神来之笔。

我个人觉得,理解

PriorityQueue
的基础用法并不复杂,核心就是那么几个方法。

首先,创建它。如果你想用默认的自然排序(比如数字从小到大),直接

new PriorityQueue<Integer>()
就行。如果你处理的是自定义对象,或者想实现大顶堆(从大到小),那就得传入一个
Comparator
。比如:

// 默认小顶堆,存储整数
PriorityQueue<Integer> minHeap = new PriorityQueue<>();

// 大顶堆,存储整数
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a); // 或者 Comparator.reverseOrder()

// 存储自定义对象,假设有一个Task类,根据priority字段排序
class Task {
    String name;
    int priority; // 优先级,数字越小优先级越高

    public Task(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    @Override
    public String toString() {
        return "Task{" + "name='" + name + '\'' + ", priority=" + priority + '}';
    }
}

PriorityQueue<Task> taskQueue = new PriorityQueue<>(Comparator.comparingInt(t -> t.priority));

接着是往里面加元素,用

add()
或者
offer()
都可以。它们俩在功能上几乎没区别,
offer()
在容量受限的队列中可能返回
false
,但
PriorityQueue
是无界的,所以一般都成功。

立即学习Java免费学习笔记(深入)”;

minHeap.add(3);
minHeap.offer(1);
minHeap.add(2);
System.out.println("当前队列 (内部表示,不保证顺序): " + minHeap); // 内部顺序不保证,但poll()会取1

然后就是取元素。

peek()
是查看队首元素,但不移除;
poll()
是取出队首元素并移除。这两个方法是用的最多的。

System.out.println("队首元素 (不移除): " + minHeap.peek()); // 输出 1
System.out.println("移除队首元素: " + minHeap.poll());    // 输出 1
System.out.println("移除后的队首元素: " + minHeap.peek()); // 输出 2
System.out.println("队列大小: " + minHeap.size());        // 输出 2
System.out.println("队列是否为空: " + minHeap.isEmpty()); // 输出 false

有时候,我发现新手会忘记

poll()
会移除元素,导致后续操作出错,所以在使用时务必明确是想“看一眼”还是“拿走”。

PriorityQueue与普通队列的本质区别在哪里?

说实话,这个问题我被问过好多次,也自己琢磨过。最核心的区别,我觉得,就在于“出队顺序”的决定机制。普通队列,比如

LinkedList
实现的
Queue
,是严格的先进先出(FIFO),你第一个放进去的,就第一个出来。这就像排队买票,谁先来谁先买。

PriorityQueue
就不同了,它关注的是“优先级”。谁的优先级高,谁就先出来,跟进队顺序无关。这就像医院的急诊室,病人来了不按先来后到,而是根据病情轻重(优先级)来决定谁先看医生。这种内在的排序机制,使得
PriorityQueue
在处理那些需要动态调整处理顺序的场景时,显得异常强大。它的底层通常是用一个二叉堆(min-heap或max-heap)来实现的,这保证了
poll()
add()
操作的平均时间复杂度是O(log n),效率相当不错。所以,如果你需要一个总是能拿到“最紧急”或“最小/最大”元素的集合,
PriorityQueue
就是你的不二之选。

如何灵活地自定义PriorityQueue的排序规则?

自定义排序规则是

PriorityQueue
非常实用的一个特性,也是我个人觉得它魅力所在的地方。Java提供了两种主要方式来实现这一点。

PatentPal专利申请写作
PatentPal专利申请写作

AI软件来为专利申请自动生成内容

下载

第一种是让你的元素类实现

Comparable
接口。如果你的对象有“自然顺序”,比如数字的大小、字符串的字典序,那么让它实现
Comparable
,并重写
compareTo
方法,
PriorityQueue
在创建时就会自动使用这个自然顺序。

class Student implements Comparable<Student> {
    String name;
    int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    // 假设分数越高优先级越高,所以是降序
    @Override
    public int compareTo(Student other) {
        return other.score - this.score; // 大顶堆,分数高的先出
    }

    @Override
    public String toString() {
        return "Student{" + "name='" + name + '\'' + ", score=" + score + '}';
    }
}

// 使用自然排序(即Student类中定义的compareTo)
PriorityQueue<Student> highScorers = new PriorityQueue<>();
highScorers.add(new Student("Alice", 90));
highScorers.add(new Student("Bob", 95));
highScorers.add(new Student("Charlie", 88));
System.out.println("最高分学生: " + highScorers.poll()); // Bob

第二种,也是更灵活的方式,是给

PriorityQueue
的构造函数传入一个
Comparator
对象。这种方式的好处是,你可以在不修改元素类的情况下,为同一个类定义多种排序规则。这在处理第三方库的类或者需要动态改变排序逻辑时特别有用。

// 使用Lambda表达式定义Comparator,实现按名字长度排序(短的优先)
PriorityQueue<String> byLength = new PriorityQueue<>(Comparator.comparingInt(String::length));
byLength.add("apple");
byLength.add("banana");
byLength.add("cat");
System.out.println("按长度排序: " + byLength.poll()); // cat

// 或者,如果想实现大顶堆(最大值优先),可以这样
PriorityQueue<Integer> customMaxHeap = new PriorityQueue<>((a, b) -> b - a);
customMaxHeap.add(10);
customMaxHeap.add(20);
customMaxHeap.add(5);
System.out.println("自定义大顶堆: " + customMaxHeap.poll()); // 20

我个人偏爱使用

Comparator
,特别是Java 8引入Lambda表达式后,写起来简直不要太方便,代码也更简洁明了。它把排序逻辑和数据结构本身的创建清晰地分开了,这在维护大型项目时尤其重要。

PriorityQueue在哪些实际场景中能发挥巨大作用?

说起

PriorityQueue
的应用场景,那可真是太广了,很多算法和系统设计都离不开它。在我看来,它就是那种“看着不起眼,但一用起来就离不开”的数据结构。

一个经典的例子是Dijkstra最短路径算法。在寻找图中两点间最短路径时,我们总是需要优先处理那些当前已知路径最短的节点。

PriorityQueue
就能完美地存储这些待处理的节点,并根据它们的当前最短距离进行排序,每次取出距离最小的节点进行扩展。没有它,Dijkstra算法的效率会大打折扣。

再比如,任务调度系统。想象一下,你有一堆任务,每个任务都有一个优先级或者一个计划执行时间。你需要一个调度器,总是能把当前最紧急或者最先到期的任务拿出来执行。

PriorityQueue
在这里就能大显身手,它能确保你总是能高效地获取到下一个需要执行的任务。

还有,“Top K”问题。比如从海量数据中找出最大的K个元素,或者最小的K个元素。这时,我们可以维护一个大小为K的

PriorityQueue
。如果是找最大的K个,就用一个小顶堆,遍历数据时,如果当前元素比堆顶元素大,就替换掉堆顶。如果是找最小的K个,就用一个大顶堆,逻辑类似。这种方法比直接排序整个数据集要高效得多,尤其是在数据量巨大的时候。

// 找出数组中最大的K个元素 (使用小顶堆)
int[] nums = {3, 2, 1, 5, 6, 4};
int k = 3;
PriorityQueue<Integer> topKHeap = new PriorityQueue<>(); // 默认小顶堆

for (int num : nums) {
    topKHeap.offer(num);
    if (topKHeap.size() > k) {
        topKHeap.poll(); // 移除最小的,保持堆中是当前遇到的K个最大元素
    }
}
System.out.println("最大的K个元素: " + topKHeap); // [4, 5, 6] (内部顺序不保证,但poll会按从小到大)

这个例子就很好的说明了,利用

PriorityQueue
的特性,我们能以相对高效的方式解决一些看似复杂的问题。

此外,事件模拟系统霍夫曼编码(Huffman Coding)构建最小生成树等算法中,

PriorityQueue
也扮演着核心角色。它提供了一种高效管理“按优先级处理”元素的机制,让复杂的问题变得清晰和可操作。所以,掌握
PriorityQueue
的使用,对于解决很多实际的编程挑战来说,绝对是一项非常值得投资的技能。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1570

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

651

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1228

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1205

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

193

2025.07.29

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

131

2025.08.07

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 82.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号