从构造方法到实战练习优先级队列 PriorityQueue

PriorityQueue优先级队列的使用和Top-k问题 阅读详情

一、前言

在 java中栈的类是 Stack,队列的接口是 Queue,并且我们通过队列的实现类 LinkedList对队列的方法进行了练习,并使用通过相关的知识完成了 LeetCode 232题 怎么用栈实现队列

了解的都知道,我这么不思进取的人怎么可能突发奇想的去了解一个工作中没用过的类,不出意外的,还是在今天做 LeetCode 347. 前 K 个高频元素题的时候,尝试了几次都不知道怎么做,看评论区发现这道题实际上应该是使用 优先级队列 来做,我才知道有优先级队列这么个东西

但是优先级队列,有的编程语言中并没有,好在 java是有的,实现优先级队列的类是 PriorityQueue,顾名思义, Priority就是优先级的意思

俗话说的好,很多东西都是你用到了才会去了解,那么今天我就和大家一起把玩把玩这个优先级队列吧

二、PriorityQueue

由于我没有下载 java8的源码,进入 PriorityQueue类里面有大量的英文注释,不方便截图,所以下面我会直接放代码

什么是优先级队列

队列我们都知道,放入元素就是放在了队尾,拿取元素就是拿取队头的元素,也就是我们常说的先进先出,那么优先级队列是什么?和队列又有什么不同?能解决什么样的问题呢?

优先级队列,依旧是 顾名思义,优先级队列会自动按照元素的权值排列,也就是说,优先级队列其实有反 先进先出规则,但是其对外接口依旧是从队头取元素,队尾添加元素,再无其他存取方式,看起来就是一个队列

优先级队列其实是一个 披着队列外皮的堆

什么是堆?

堆通常可以被看成一个完全二叉树的数组对象,树中的每个节点都不小于(或不大于)其左右孩子的值

  • 如果父节点大于左右孩子的值,那么是大顶堆
  • 如果父节点小于左右孩子的值,那么是小顶堆

优先级队列的特点

  • 优先级队列里的元素必须实现内部比较器或者外部比较器
  • 优先级队列拥有小顶堆的所有特性, 默认是 小顶堆
  • 优先级队列不是线程安全的
  • 不允许使用 null元素
  • 优先级队列本身是无序的,但是取出的元素所排成的序列才是有序序列

关于特点部分来源于百度,有问题的话及时评论指正,谢谢

基本属性

// 序列化相关,可以忽略
private static final long serialVersionUID = -7720805057305804111L;
// 默认无参构造时数组的长度
private static final int DEFAULT_INITIAL_CAPACITY = 11;
// 存储元素的数组队列
transient Object[] queue;
// 
private int size = 0;
// 集合排序策略
private final Comparator<? super E> comparator;
// 
transient int modCount = 0;

构造方法

我将下面三个构造方法分为一类,最主要的第四个构造方法,其他三个是方法重载, DEFAULT_INITIAL_CAPACITY上面有说,是值默认无参构造时队列的长度 comparator是指优先级排序的规则, 默认来说优先取的是权值小的

第四个构造方法就是初始化了队列数组的长度,同时设置了比较器


public PriorityQueue() {
    this(DEFAULT_INITIAL_CAPACITY, null);
}

public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

public PriorityQueue(Comparator<? super E> comparator) {
    this(DEFAULT_INITIAL_CAPACITY, comparator);
}

public PriorityQueue(int initialCapacity,
                     Comparator<? super E> comparator) {
    if (initialCapacity < 1)
        throw new IllegalArgumentException();
    this.queue = new Object[initialCapacity];
    this.comparator = comparator;
}


下面是对 PriorityQueue构造方法的测试,可以发现,我们调用 PriorityQueue.size()方法的时候返回的并不是我们设置的队列长度,而是元素的数量,留下一个疑问,一会我们一起看一下

下面的这几个构造方法就会稍微复杂一点了

// 包含优先级元素

public PriorityQueue(PriorityQueue<? extends E> c) {
    this.comparator = (Comparator<? super E>) c.comparator();
    initFromPriorityQueue(c);
}

下图是通过上面的构造函数进行构造的,真是有趣极了,大家可以看到,priorityQueue4是按照我们设置的规则进行了降序排列,没有问题,但是 priorityQueue5继承了 priorityQueue4的元素和比较器之后打印出来的却不完全是按照顺序打印的,后面四个元素变成了 2,1,2,1,到最后面遍历的时候却又是按照了2,2,1,1顺序打印的

创建含有指定顺序set元素的 PriorityQueue

public PriorityQueue(SortedSet<? extends E> c) {
    this.comparator = (Comparator<? super E>) c.comparator();
    initElementsFromCollection(c);
}

具体测试代码如下所示,和入参为 PriorityQueue类一样,都是继承了其类的比较器

下面这个构造方法,集成了上两个构造方法,他们最后调用的方法主要就是初始化数组,里面各种跳转,感兴趣的可以自己看一下

public PriorityQueue(Collection<? extends E> c) {
    if (c instanceof SortedSet<?>) {
        SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
        this.comparator = (Comparator<? super E>) ss.comparator();
        initElementsFromCollection(ss);
    }
    else if (c instanceof PriorityQueue<?>) {
        PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
        this.comparator = (Comparator<? super E>) pq.comparator();
        initFromPriorityQueue(pq);
    }
    else {
        this.comparator = null;
        initFromCollection(c);
    }
}

常用方法

  • add/offer: 添加元素
  • element/peek:返回元素不删除
  • remove/poll:弹出元素,并删除
  • remove:删除元素,若元素有多个则只删除一个

add, element, 无参remove()方法不建议使用,若失败会抛出异常

三、实践出真知,LeetCode走起

不知道你是不是和我一样,看完就会,上手就废型选手,废话不多说,上链接 347. 前 K 个高频元素

题目描述

解题思路

  • 很明显是要用优先级队列来做,而且这里需要注意的是优先级队列默认是升序排列,我们这边要给他变成降序,因为弹出的时候优先弹出次数多的
  • 首先定义一个返回值 int数组 result,长度就是 k,毕竟是让我们返回前 k的元素
  • 在创建一个 map对象,key是数字,value是出现的次数
  • 遍历 nums对象,查看 map中是否存在当前元素,存在则 value++,不存在则新增,value = 1
  • 创建优先级队列 queue
  • 获取到 map的 Map.EntrySet对象,因为我们要自定义一个降序排列的比较器
    • 这里不能直接使用 Collections.reverseOrder(),因为我们是对 map中的 value,当前数字出现的次数进行比较
  • 遍历 entries,然后将获取到的 map加入到 queue队列中
  • 之后直接遍历队列,因为我们是优先级队列,而且设置了比较器,所以直接 queue.poll()方法就可以,会弹出当前队列最大的元素,且在队列中删除该元素
    • 终止条件是 k,因为题中要求的就是返回长度为 k的数组,多了该越界了

代码展示

public static int[] topKFrequent(int[] nums, int k) {
    int[] result = new int[k];
    // 优先级队列元素
    Map<Integer,Integer> map = new HashMap<>();
    // 遍历 nums获取元素及其出现次数
    for (int i = 0; i < nums.length; i++) {
        int num = nums[i];
        map.put(num, map.getOrDefault(num, 0 ) + 1);
    }
    Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
    PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o2.getValue() - o1.getValue());
    for (Map.Entry<Integer, Integer> entry : entries) {
        queue.add(entry);
    }
    for (int i = 0; i < k; i++) {
        result[i] = queue.poll().getKey();
    }
    return result;
}

提交结果

四、总结

很多东西都是你用到了才会去了解,如果可以的话,还是提前了解的比较好,防止出现像我一样的情况:等到需要了我却不知道

那句话怎么说的来着,书到用时方恨少,加油

Java【优先级队列】详细图解 / 模拟实现 + 【PriorityQueue】常用方法介绍 优先级队列并不是像普通普通的队列那样永远遵从先进先出, 而是有优先级的, 出队时让优先级高的先出队上篇文章说过, 二叉树是一种逻辑结构, 物理结构上可以是顺序存储, 也可以是链式存储, 而堆就是在顺序存储的二叉树上做了调整PriorityQueue底层使用了堆这种数据结构堆的概念: 如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki 阅读详情

相关推荐

优先级队列(PriorityQueue)

Java集合框架中提供了和两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,本文主要介绍PriorityQueue。关于PriorityQueue的使用要注意:2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出异常.那重写方法能不能改变不能比较得现状呢?回答:3. 不能插入null对象,否则会抛出NullPointerException(空指针异常)4.没有容量限制。

YQY18289570091的博客 1003

【Java】PriorityQueue--优先级队列

前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话. 在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。

weixin_73616913的博客 1万+

详解PriorityQueue

可以通过传递一个Comparator来实现最大堆。// 创建一个最大堆 PriorityQueue// 添加元素// 输出队列中的元素(按优先级顺序)while (!// 每次取出优先级最高的元素输出复制5321。

liuyuzhongcc的博客 1232

PriorityQueue

PriorityQueue

aloserbird的博客 505

可信数据空间:可信空间、区域功能节点、业务功能节点、连接器的关联关系

可信数据空间通过分层架构实现安全数据共享:可信空间作为顶层制定全局规则;区域功能节点协调辖区内功能节点协作;功能节点提供具体数据服务;连接器作为唯一通信通道确保安全交互。系统采用"规则自上而下约束,数据自下而上流动"机制,通过分层治理和标准化连接,在保证数据主权的同时实现跨域协作,具有策略分级执行、去中心化治理等特性,支持灵活扩展业务场景。

友莘居士的博客 1686

IP路由原理、静态路由及动态路由区分

什么是路由 路由是指导IP报文发送的路径信息。 直连路由:目的地所在网络与路由器直接相连。 间接路由:目的地所在网络与路由器非直接相连。 静态路由是由管理员手工配置而生成的路由。 动态路由路由器使用路由协议从其他路由器那里获悉的路由。

weixin_42227328的博客 5470

PriorityQueue的介绍,底层重要源码的分析,以及PriorityQueue的应用

目录 1.PriorityQueue接口的介绍 2.PriorityQueue底层源码的分析 3.PriorityQueue的应用 1.PriorityQueue接口的介绍 1.1.PriorityQueue的特性 1.PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常 2. 不能插入null对象,否则会抛出NullPointerException,而Queue是可以插入null的 .

xaiobit_hl的博客 1390

Macbook Pro上如何修改brew源

一、需求说明 我的macbook电脑安装了中科大的brew源码,发现安装gpg工具失败,其他工具可以正常安装,为了能将gpg安装成功,就找了找切换brew源的方案,记录如下。 二、切换至国内源 由于使用github默认源有可能存在路径远或者部分服务访问超时的原因,切换至国内源可以提速。 2.1 替换brew.git $ cd "$(brew --repo)" # 中国科大: $ git remote set-url origin https://mirrors.ustc.edu.cn/brew.git #

bufegar0的博客 1079

数据结构:优先级队列— PriorityQueue

在Java中自带了一种优先级队列:PriorityQueue,它保证了每次取出的元素都是队列中最小或最大的,并且他的形态采用树形结构,通过实现一个完全二叉树的最小堆或最大堆来实现队列的排序。

zm3rttqs9f的博客 2683

【processing】创意编程

首先接到这个作业的时候,我是很崩溃的,我是真的不会画画QAQ,还画自己,这也太难了,于是我决定!还是祸害我爱豆吧!于是我从微博太太那里找了个图临摹 下面是太太的图 先给太太道歉!都是为了作业! 然后我画出来是这样子的 还可以!!!没有特别丑!(虽然也不是特别像吧) 但是画这个真是画死我了,下面贴上代码吧,没啥特殊的就是各种贝塞尔曲线各种圆各种线 //face stroke(70,27,11...

qq_25700571的博客 1267

Open3D 从体素网格构建八叉树【2025最新版】

从体素网格构建八叉树,博客长期更新,本文最近更新时间为:2025年1月1日。

点云侠的博客 34万+

PriorityQueue的详解

问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了。故创建PriorityQueue()时数组的默认容量是11;// 用ArrayList对象来构造一个优先级队列的对象。以上为我个人的小分享,如有问题,欢迎讨论!---即每次获取到的元素都是最小的元素,个元素依次与堆顶元素比完之后,堆中剩余的。都看到这了,不如关注一下,给个免费的赞。,因为Student的比较对象不明确。(1)offer底层代码展示。两种类型的优先级队列,个最小或者最大的元素。(1)使用时必须导入。

WHabc2002的博客 321

卫朋:IPD流程落地——产品计划阶段拆解

IPD计划阶段拆解

产品线负责人 957

Java数据结构 | PriorityQueue详解

一文带你学透PriorityQueue

m0_56361048的博客 3842

揭秘大厂 Unity 红点系统设计:别小看右上角那颗小红点,它能把你项目搞崩

本文详细探讨了游戏大厂如何设计高性能红点系统。红点作为提升用户活跃和转化率的重要工具,需要支持多级联动、动态判断和全局一致性。系统采用观察者模式和树形结构,分为数据管理、逻辑判定、订阅通知和UI展示四大模块,通过事件驱动方式实现高效刷新。文章特别强调了解耦设计、配置化管理和性能优化,并提出了热更新、数据分析等高级应用场景。最终指出,优秀的红点系统需要架构标准化、自动化配置和团队紧密协作,是大型游戏项目的关键技术基础。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 377

使用 MATLAB/Simulink 对基于同步发电机的双机系统进行建模,并对其在短路故障条件下的暂态稳定性进行仿真和分析

双机系统(Two-Machine System)是电力系统中用于研究动态稳定性和控制策略的一个典型模型。它由两台同步发电机通过输电网络相互连接,模拟实际电网中的互联操作。当发生短路故障时,系统的暂态稳定性会受到挑战,可能导致发电机失步或电压崩溃。本教程将带你使用 MATLAB/Simulink 对基于同步发电机的双机系统进行建模,并对其在短路故障条件下的暂态稳定性进行仿真和分析。

amy_mhd的博客 8506

数据结构优先级队列PriorityQueue

我们使用大根堆来进行排序,将0下标值与最后下标值进行交换,end为最后下标值,然后向下筛选重新获取最大的节点值,每次的有效元素数量-1(由最后一个下标开始–直到为0,获取由小到大的元素)。而优先级队列(PriorityQueue)指的是具有优先级别的队列(特殊队列),根据指定类型的大小,每次出队的元素都是该类型中最大或者是最小的值,具有优先级。删除元素我们可以将对首的元素将队尾的元素进行互换,并将队尾元素的下标值删除,后续进行覆盖,然后通过向下筛选,设定根节点为0下标互换的位置,进行向下筛选。

Freedom的博客 3201

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Java中的优先级队列(PriorityQueue)(如果想知道Java中有关优先级队列的知识点,那么只看这一篇就足够了!)

Java中的优先级队列(PriorityQueue)(如果想知道Java中有关优先级队列的知识点,那么只看这一篇就足够了!)

秋刀鱼不做梦的编程日常 9503

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Java集合框架:优先级队列、PriorityQueue详解

堆的本质就是一颗完全二叉树,如上图所示;用顺序存储的方式来进行存储(如果是非完全二叉树,不宜采用顺序方式来存储数据,此时会有数组空间的浪费)。大根堆如果一组数据集合中的所有的元素按照完全二叉树的顺序存储方式来进行存储,并且根节点都大于左右孩子节点,此时这个就称作大根堆。小根堆和大根堆类似,本质也是用顺序存储的方式存储的一颗二叉树,并且根节点小于左右孩子节点,此时称作这个堆为小根堆。而优先级队列的本质就是一个大根堆或者小根堆。

weixin_64874291的博客 5184

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

【Java--数据结构】优先级队列( PriorityQueue)

优先级队列是一种特殊的队列,它在入队时会根据元素的优先级进行排序,优先级最高的元素排在队列的前面,出队时会优先出队优先级最高的元素。核心特点:元素按优先级排序,每次取出优先级最高(或最低)的元素 PriorityQueue类底层使用堆这种数据结构,堆适用于完全二叉树堆是一种特殊的完全二叉树数据结构完全二叉树:除了最后一层外,每一层的节点数都是满的,并且最后一层的节点都靠左排列。堆的分类:(1)最大堆:父节点 ≥ 子节点,根节点为全局最大值。(2)最小堆:父节点 ≤ 子节点,根节点为全局最小值。(1)堆序性:

我的博客 3001

优先级队列(堆) PriorityQueue

队列是一种先进先出的数据结构,但是在有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的先出队列,在这种情况下,使用先进先出的队列显然不合适。关于向下调整的时间复杂度分析,最坏的情况即,从根一路比较到叶子,则比较的次数为二叉树的高度,时间复杂度则为 O(若2*(i+1)

m0_74294415的博客 915

优先级队列(PriorityQueue)和堆

前面介绍过队列,是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有,一般出队列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话;初中那会班主任排座位时可能会让成绩好的同学先挑座位。在这种情况下,数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是。

weixin_63189874的博客 3310

优先级队列和PriorityQueue

优先级队列是一种特殊的队列,每个元素都有一个优先级或者权重,与普通队列的先进先出不同,它按照优先级的大小从高到低进行排序,优先级最高的优先出队列。在任务调度,事件模拟中发挥着重要的作用。Java中的优先级队列是一种利用堆这种数据结构进行实现,按照数据的优先级顺序进行排序,可以任意的顺序插入,但是取出时按照规定好的优先级进行操作。

2301_79985750的博客 978

优先级队列PriorityQueue(堆)

堆的一些碎碎念

2201_75880772的博客 2294

Java数据结构(七)——优先级队列与PriorityQueue

文章基于Java集合框架中的PriorityQueue类,先介绍了堆的相关知识,而后介绍了PriorityQueue的使用。

xiaokuer_的博客 1526
上一篇: Java 并发编程解析 | 如何正确理解Java领域中的并发锁,我们应该具体掌握到什么程度?
下一篇: 易学易爆炸!阿里P8耗时90天,为你分析分布式系统技术和实战笔记
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值