Java PriorityQueue优先级队列的使用方式

 更新时间:2026年02月02日 15:51:16   作者:吞吞吐吐大魔王  
PriorityQueue是一个优先级队列,可以按照优先级处理对象,它继承了Queue接口,底层是一个堆,可以实现大根堆或小根堆,常用方法包括offer、poll、peek、size等,插入元素时需要注意元素不能为null并且必须能够进行比较,大根堆可以通过传入自定义的比较器实现

1. 场景引入

我们知道,Queue是一个先进先出(FIFO)的队列。

在很多应用中,我们通常需要按照优先情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏时,如果有来电,那么系统应该优先处理进来的电话。

这个时候,我们发现,要实现上述的操作,用Queue就不行了,因为Queue会严格按 FIFO 的原则取出队首元素。故有了我们需要的优先队列:PriorityQueue

2. PriorityQueue 介绍

Java 中 PriorityQueue 继承了 Queue 接口,它的底层是一个堆。

3. 知识点

PriorityQueue 的底层是一个数组

我们可以转到它的定义,可以看到它的底层定义是一个数组。为了知道这个数组的初始大小有多大

再通过它的参构造方法转到定义,又可以看到

再点击 this,转到其定义,我们发现又跳到了一个含两个参数的构造方法

又在 PriorityQueue 的定义中 DEFAULT_INITIAL_CAPACITY = 11,即 initialCapacity = 11,所以我们可以知道数组的初始大小为11

PriorityQueue 的底层默认是一个小根堆

如何使 PriorityQueue 的底层是一个大根堆?

引用上图 PriorityQueue 的含参定义,我们知道第一个参数代表数组的大小,而第二个参数就一个比较器,传给他的就是比较的方法,通过给他传入大根堆的比较方式,我们就可以使 PriorityQueue 的底层变成大根堆

4. 常用方法

方法描述
boolean offer(E e)入队列
E poll()出队列
E peek()得到队首元素
int size()返回集合中的元素个数

注意: 下面的示例都是一份代码分开拿出来的,上下其实是有逻辑关系的

  • 示例一: 用 Priority Queue 创建一个优先级队列
PriorityQueue<Integer> queue=new PriorityQueue<>();
  • 示例二: 入队列
queue.offer(10);
queue.offer(2);
queue.offer(5);
  • 示例三: 得到队首元素
System.out.println(queue.peek());
// 结果为:2
  • 示例四: 出队列
System.out.println(queue.poll());
// 结果为:2
  • 示例五: 返回集合中元素个数
System.out.println(queue.size());
// 结果为:2

5. 优先级队列插入元素的细节问题

当我们使用优先级队列的时候,插入元素其实有个前提:

插入的元素不能是 null 或者元素之间必须能够进行比较

而基本的包装类类型都可以进行比较,如:Integer、Double、Float。但是对于我们自定义的类型,其实就可能不能比较,就如下面这个类当我们使用优先级队列对它的对象进行插入时,其实会报错

class Student{
    private String name;
    private int age;

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
    }
}
public class TestDemo{
    public static void main(String[] args){
        PriorityQueue<Student> queue=new PriorityQueue<>();
        queue.offer(new Student("Tom",18));
        queue.offer(new Student("Hen",34));
    }
}

这是因为优先级队列的底层默认是一个小根堆,它存入元素时是需要进行比较对象的大小的。

我们可以转到 PriorityQueue 的无参构造方法的定义看看

此时我们的 comparator 默认是 null,我们再转到 offer 方法的定义看看

好像并没有什么异常,但是由于我 插入第二个元素时,i 不为0,所以要进行 siftUp 方法,我们转到它的定义

由于我们知道 comparator 为 null,那么则要进行 siftUpComparable 方法,继续转到它的定义

我们发现,创建的 Student 的对象,被强转为了 Comparable<? super E>,并且还调用了 compareTo 方法。

如果大家有看过我写的 解析 Java 的多态、抽象类和接口Java 对象的比较 这两篇文章,那我就有讲到 compareTo 这个方法。这个方法是 Comparable 的一个抽象方法,定义的是比较对象大小的一个规则。

因此为了解决这个问题,我们就可以使用和 Comparable 或 Comparator 接口相关的知识

6. PriorityQueue 大根堆的创建方式

6.1 思路

这里便不对源码做具体分析,我们如果要 PriorityQueue 创建出的是一个大根堆,只需要对具体类型写一个比较器即可

6.2 代码实现

// 定义的某个要比较类型的比较器
class IntegerComparator implements Comparator<Integer>{
    @Override
    public int compare(Integer o1,Integer o2){
        // 如果第二个元素-第一个元素就是大根堆的实现方式,反之则为小根堆的创建方式,可以从源码去了解
        return o2-o1;
    }
}
public class TestDemo{
    public static void main(String[] args){
        PriorityQueue<Integer> maxHeap=new PriorityQueue<>(IntegerComparator);
    }
}

6.3 使用匿名内部类

上述代码也可以写成

public class TestDemo{
    public static void main(String[] args){
        PriorityQueue<Integer> maxHeap=new PriorityQueue<>(new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                return o2-o1;
            }
        })
    }
}

这相当使用了一个匿名的内部类的方式去创建大根堆

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中的LinkedHashSet解析

    Java中的LinkedHashSet解析

    这篇文章主要介绍了Java中的LinkedHashSet解析,与HashSet不同的是,LinkedHashSet在内部使用了一个双向链表来维护元素的顺序,因此它可以保持元素的插入顺序,这使得LinkedHashSet在需要保持元素顺序的场景下非常有用,需要的朋友可以参考下
    2023-11-11
  • MybatisPlus只取一条记录的两种方法实现

    MybatisPlus只取一条记录的两种方法实现

    本文介绍了MyBatis-Plus2.x和3.x版本在IService接口获取单条记录的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-07-07
  • java 中 zookeeper简单使用

    java 中 zookeeper简单使用

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。下面通过本文给大家分享java 中 zookeeper简单使用,需要的朋友参考下吧
    2017-09-09
  • Log4j 配置日志打印时区的实现方法

    Log4j 配置日志打印时区的实现方法

    下面小编就为大家分享一篇Log4j 配置日志打印时区的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • java蓝桥杯试题

    java蓝桥杯试题

    这篇文章主要介绍了java蓝桥杯试题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • SpringBoot 使用@WebMvcTest测试MVC Web Controller

    SpringBoot 使用@WebMvcTest测试MVC Web Controller

    这篇文章主要介绍了SpringBoot 使用@WebMvcTest测试MVC Web Controller,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • SpringBoot集成MinIO实现高效文件存储的实战方案

    SpringBoot集成MinIO实现高效文件存储的实战方案

    在后端开发中,文件存储是高频需求,传统本地存储存在扩展性差、集群部署不便、数据易丢失等问题,MinIO作为开源高性能对象存储服务,可轻松实现文件的上传、下载、预览、删除等功能,本文聚焦SpringBoot与MinIO的实战落地,实现高效文件管理,需要的朋友可以参考下
    2026-01-01
  • Apache CXF如何把wsdl生成java代码

    Apache CXF如何把wsdl生成java代码

    这篇文章主要介绍了Apache CXF如何把wsdl生成java代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • 浅谈Spring-cloud 之 sleuth 服务链路跟踪

    浅谈Spring-cloud 之 sleuth 服务链路跟踪

    本篇文章主要介绍了浅谈Spring-cloud 之 sleuth 服务链路跟踪,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • SpringBoot之瘦身部署的详细步骤

    SpringBoot之瘦身部署的详细步骤

    本篇文章主要介绍了SpringBoot之瘦身部署的详细步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08

最新评论