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

        前言:优先级队列(Priority Queue)是一种抽象数据类型,其中每个元素都关联有一个优先级,元素按照优先级顺序进行处理。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

先让我们看一下本文大致的讲解内容:

目录

1.优先队列的初识

        (1)优先级队列的定义

        (2)PriorityQueue的特性

2.优先级队列的模拟实现

3.优先级队列中常用API

        (1)创建优先级队列

        (2)插入/删除/获取优先级最高的元素/获取个数/清空/判断是否为空

4.优先级队列的使用

1. 任务调度

2. 事件驱动模拟

3. 图算法

4. 数据流处理


1.优先队列的初识

        (1)优先级队列的定义

        在开始学习Java中优先级队列的使用之前,先让我们了解一下什么是Java中的优先级队列(PriorityQueue):

        优先级队列(Priority Queue)是一种抽象数据类型,其中每个元素都关联有一个优先级,元素按照优先级顺序进行处理。与标准队列不同,优先级队列中的元素处理顺序并非按插入顺序,而是按照优先级高低来决定。

        如果读者看了优先级队列的定义之后还是不是太理解什么是优先级队列,那么现在我们使用一个日常生活中的例子来帮助你理解:

        ——例如在医院急诊室,虽然你可能先到,但是医生会根据病人的病情严重程度来决定治疗顺序。病情严重的病人(例如,心脏病发作的病人)会被优先治疗,而病情较轻的病人(例如,轻微的感冒)会被安排在后面。

        这样我相信读者就对优先级队列有了初步的认识了!!!

        (2)PriorityQueue的特性

        Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队,而对于PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,而本文我们主要介绍是PriorityQueue。

其在Java集合框架中的关系图为:

关于PriorityQueue的使用要注意:

        1. 使用时必须导入PriorityQueue所在的包,即:

import java.util.PriorityQueue;

        2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出ClassCastException异常;

        3. 不能插入null对象,否则会抛出NullPointerException;

        4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容;

        5. 插入和删除元素的时间复杂度为O(logN);

        6. PriorityQueue底层使用了堆数据结构;

        7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素;

        至此,我们通过上述对Java中的优先级队列的简单讲述,我们就大致的了解了什么是Java中的优先级队列了!

2.优先级队列的模拟实现

        在了解完了什么是Java中的优先级队列之后,现在让我们想想看如何去自我实现一个Java中的优先级队列呢?

——这里我们已经在每处加上了注释,希望读者可以跟随着注释进行理解代码:

package Demo1;import java.util.Arrays;// 堆的自我实现 - 创建堆 + 插入数据 + 删除数据 + 返回堆顶元素 + 判断是否为空
public class MyPriorityQueue {public int[] elem; // 存储堆元素的数组public int useSize; // 当前堆中元素的个数// 初始化堆public MyPriorityQueue(int[] array) {elem = new int[11]; // 初始化堆的容量for (int i = 0; i < array.length; i++) {elem[i] = array[i]; // 将传入的数组元素放入堆中useSize++; // 更新堆中元素的个数}makeBigHeap(array, useSize); // 创建大根堆}// 整体创建堆public void makeBigHeap(int[] array, int useSize) {// 从最后一个非叶子节点开始向上调整for (int parent = (useSize - 1 - 1) / 2; parent >= 0; parent--) {shiftDown(parent, useSize); // 对每个非叶子节点进行下沉操作}}// 下沉操作private void shiftDown(int root, int useSize) {int child = 2 * root + 1; // 左子节点索引while (child < useSize) { // 遍历堆// 如果右子节点存在且右子节点的值大于左子节点的值,选择右子节点if (child + 1 < useSize && elem[child] < elem[child + 1]) {child++;}// 如果当前节点的值小于子节点的值,交换它们if (elem[root] < elem[child]) {swap(root, child);root = child; // 更新根节点为被交换的子节点child = 2 * root + 1; // 更新左子节点的索引} else {break; // 如果根节点的值不小于任何子节点,退出循环}}}// 在堆中插入元素private boolean isFull() {return useSize == elem.length; // 判断堆是否满了}public void offer(int val) {if (isFull()) {elem = Arrays.copyOf(elem, 2 * elem.length); // 扩容}elem[useSize] = val; // 将新元素放入堆的末尾shiftUp(useSize); // 上浮操作调整堆useSize++; // 更新堆中元素的个数}// 上浮操作private void shiftUp(int child) {int parent = (child - 1) / 2; // 计算父节点的索引while (parent >= 0) {// 如果当前节点的值大于父节点的值,交换它们if (elem[parent] < elem[child]) {swap(parent, child);child = parent; // 更新子节点为被交换的父节点parent = (child - 1) / 2; // 更新父节点的索引} else {break; // 如果当前节点的值不大于父节点的值,退出循环}}}// 删除堆中元素public void poll() {if (isEmpty()) {throw new RuntimeException("堆中元素为空!"); // 如果堆为空,抛出异常}swap(0, useSize - 1); // 将堆顶元素与最后一个元素交换useSize--; // 更新堆中元素的个数shiftDown(0, useSize); // 对堆顶元素进行下沉操作}// 获取堆顶元素public int peek() {if (isEmpty()) {throw new RuntimeException("堆中元素为空!"); // 如果堆为空,抛出异常}return elem[0]; // 返回堆顶元素}// 判断堆是否为空private boolean isEmpty() {return useSize == 0; // 如果堆中没有元素,返回 true}// 交换数组中的两个元素private void swap(int pos1, int pos2) {int temp = elem[pos1];elem[pos1] = elem[pos2];elem[pos2] = temp;}
}
public class Test {public static void main(String[] args) {// 初始化一个整数数组int[] array = {1, 4, 2, 7, 9, 10, 5, 6, 8, 3};// 创建一个优先级队列实例MyPriorityQueue myPriorityQueue = new MyPriorityQueue(array);// 向优先级队列中插入多个元素myPriorityQueue.offer(5);myPriorityQueue.offer(3);myPriorityQueue.offer(8);myPriorityQueue.offer(1);// 打印堆顶元素System.out.println(myPriorityQueue.peek());// 删除堆顶元素myPriorityQueue.poll();// 判断堆是否为空,并打印结果(注意这里原代码并未打印结果,需手动添加打印语句)System.out.println("堆是否为空: " + myPriorityQueue.isEmpty());}
}

        从中我们可以看到我们使用堆这个数据结果来自我实现了从 - 创建堆 - 插入数据 - 删除数据 - 返回堆顶元素 - 判断是否为空等优先队列中的操作。至此我们完成了自我实现Java中的优先级队列(PriorityQueue)。

如果对于堆这种数据结构不了解的读者,可以阅读---------->Java中的Heap(堆)(如果想知道Java中有关堆的知识点,那么只看这一篇就足够了!)-CSDN博客

3.优先级队列中常用API

        通过上面的学习,我们已经了解了什么是Java中的优先级队列,并且自我实现了优先级队列,现在让我们看看Java中内置的优先级队列该如何使用吧!

        (1)创建优先级队列

PriorityQueue类提供了多种构造方法,允许创建不同配置的优先级队列。

构造器功能
PriorityQueue()创建一个空的优先级队列,默认容量是11
PriorityQueue(int initialCapacity)创建一个初始容量为initialCapacity的优先级队列,注意:
initialCapacity不能小于1,否则IllegalArgumentException异常
PriorityQueue(Collection<? extends E> c)

用一个集合来创建优先级队列

例子:

import java.util.PriorityQueue;public class PriorityQueueDemo {public static void main(String[] args) {// 默认初始容量的优先级队列PriorityQueue<Integer> pq = new PriorityQueue<>();// 指定初始容量的优先级队列PriorityQueue<Integer> pqWithCapacity = new PriorityQueue<>(20);// 使用比较器的优先级队列PriorityQueue<Integer> pqWithComparator = new PriorityQueue<>(new CustomComparator());}
}

        ——这样我们就会常见Java中的优先级队列了!

在了解了如何创建一个优先级队列之后,接下来让我们看一下如何去操作这个创建的优先级队列。

        (2)插入/删除/获取优先级最高的元素/获取个数/清空/判断是否为空

函数名功能
boolean offer(E e)插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度O(logN),注意:空间不够时候会进行扩容
E peek()获取优先级最高的元素,如果优先级队列为空,返回null
E poll()移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size()获取有效元素的个数
void clear()清空
boolean isEmpty()检测优先级队列是否为空,空返回true

例子:

import java.util.PriorityQueue;public class Test {public static void main(String[] args) {// 初始化一个整数数组int[] arr = {4, 1, 9, 2, 8, 0, 7, 3, 6, 5};PriorityQueue<Integer> q = new PriorityQueue<>(arr.length);// 将数组中的元素添加到优先级队列中for (int e : arr) {q.offer(e);}// 打印优先级队列中有效元素的个数System.out.println(q.size());// 获取并打印优先级队列中优先级最高的元素(即最小值,因为是最小堆)System.out.println(q.peek());// 从优先级队列中删除两个元素q.poll();q.poll();// 打印删除两个元素后,优先级队列中有效元素的个数System.out.println(q.size());// 获取并打印当前优先级最高的元素System.out.println(q.peek());// 向优先级队列中插入一个新的元素q.offer(0);// 获取并打印插入新元素后的优先级最高的元素System.out.println(q.peek());// 清空优先级队列中的所有有效元素q.clear();// 检测优先级队列是否为空,并打印结果if (q.isEmpty()) {System.out.println("优先级队列已经为空!!!");} else {System.out.println("优先级队列不为空");}}
}

        ——这样我们就大致的了解了如何操作Java中的优先级队列了!!!

4.优先级队列的使用

        优先级队列(Priority Queue)是一种特殊的数据结构,用于处理具有优先级的元素。它的主要特点是能够高效地插入元素并以优先级顺序访问和删除元素。以下是优先级队列的一些主要应用场景:

1. 任务调度

  • 场景: 操作系统和调度系统常常需要管理多个任务,每个任务具有不同的优先级。

  • 用法: 优先级队列可以用来实现任务调度系统,其中优先级高的任务会被优先执行。比如,操作系统的进程调度器会使用优先级队列来决定哪个进程应该优先获得 CPU 时间。

2. 事件驱动模拟

  • 场景: 在模拟系统(如网络仿真或离散事件模拟)中,事件会在未来的某个时间点发生。

  • 用法: 优先级队列用于存储和处理这些事件,确保在模拟中按事件的发生时间顺序处理它们。

3. 图算法

  • 场景: 在计算图的最短路径(如 Dijkstra 算法)或最小生成树(如 Prim 算法)时,需要按边的权重或节点的距离进行操作。

  • 用法: 使用优先级队列可以有效地管理和访问图中的边或节点,以支持这些算法的高效执行。

4. 数据流处理

  • 场景: 数据流中的数据可能具有不同的重要性或优先级。

  • 用法: 在处理实时数据流时,优先级队列可以用来根据数据的优先级顺序处理数据。

这样我们就大致的了解了Java中的优先级队列在日常中的使用地方了!


以上就是本篇文章的全部内容了~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/876439.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

足浴行业押金原路退回怎么开通?

一手机版和电脑版差别 手机版押金管理的优点&#xff1a; 1. 便携性&#xff1a;管理人员可以随时随地通过手机查看和处理押金相关事务&#xff0c;不受地点限制。例如&#xff0c;当不在店内时&#xff0c;仍能及时了解押金的收支情况&#xff0c;对突发问题进行处理。 2. 实…

基于微信小程序的校园二手交易平台/Java的二手交易网站/基于Javaweb校园二手商品交易系统(附源码)

摘 要 使用校园二手交易平台管理校园二手物品交易&#xff0c;不仅实现了智能化管理&#xff0c;还提高了管理员的管理效率&#xff0c;用户查询的功能也需要校园二手交易平台来提供。 设计校园二手交易平台是毕设的目标&#xff0c;校园二手交易平台是一个不断创新的系统&…

【通信模块】简单玩转WiFi模块(ESP32、ESP8266)

笔者学习太极创客的学习笔记&#xff0c;链接如下&#xff1a;www.taichimaker.com 前期准备 电脑端口 固件烧录 WIFI到网页 对应七层网络协议 WIFI工作模式&#xff08;链路层&#xff09; 接入点模式、无线中断模式、混合模式 IP协议&#xff08;网络层&#xff09; 子网…

Kafka知识总结(选举机制+控制器+幂等性)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 选举机制 控制器&#xff08;Broker&#xff09;选举 控制器就是…

springboot使用Gateway做网关并且配置全局拦截器

一、为什么要用网关 统一入口&#xff1a; 作用&#xff1a;作为所有客户端请求的统一入口。说明&#xff1a;所有客户端请求都通过网关进行路由&#xff0c;网关负责将请求转发到后端的微服务 路由转发&#xff1a; 作用&#xff1a;根据请求的URL、方法等信息将请求路由到…

【初阶数据结构篇】时间(空间)复杂度

文章目录 算法复杂度时间复杂度1. 定义2. 表示方法3. 常见时间复杂度4.案例计算分析冒泡排序二分查找斐波那契数列&#xff08;递归法&#xff09;斐波那契数列&#xff08;迭代法&#xff09; 空间复杂度案例分析冒泡排序斐波那契数列&#xff08;递归法&#xff09;斐波那契数…

【漏洞复现】ServiceNow UI Jelly模板注入(CVE-2024-4879)

声明&#xff1a;本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动&#xff0c;将与本文档的作者或发布者无关。 一、漏洞描述 ServiceNow是一家专注于提供企业级云计算服务的企业&#xff0c;其旗舰产品是基于云的服务管理解决方案&…

视觉巡线小车(STM32+OpenMV)——总结

文章目录 目录 文章目录 前言 一、效果展示 二、完整流程 1、STM32CubeMX配置 2、Keil编辑 3、硬件接线 4、参数调试 5、图像处理调试 三、总结 前言 基于前面的系列文章&#xff0c;已基本介绍完了基于STM32OpenMV的视觉巡线小车&#xff0c;本文将以小编自己的小车…

SeaCMS海洋影视管理系统远程代码执行漏洞复现

SeaCMS海洋影视管理系统远程代码执行漏洞复现 Ⅰ、环境搭建Ⅱ、漏洞复现Ⅲ、漏洞分析 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&…

全栈嵌入式C++、STM32、Modbus、FreeRTOS和MQTT协议:工业物联网(IIoT)可视化系统设计思路(附部分代码解析)

项目概述 随着工业4.0时代的到来&#xff0c;工业物联网&#xff08;IIoT&#xff09;在提高生产效率、降低运营成本和实现智能制造方面得到了广泛应用。本项目旨在开发一个全面的工业物联网监控系统&#xff0c;能够实时监测设备的温度、压力、振动和电流等参数&#xff0c;并…

【Python实战因果推断】60_随机实验与统计知识2

目录 An A/B Testing Example An A/B Testing Example 在许多公司中&#xff0c;一种常见的策略是提供廉价甚至免费的产品&#xff0c;这种产品本身可能并不盈利&#xff0c;但其目的是吸引新客户。一旦公司获得了这些客户&#xff0c;就可以向他们推销其他更盈利的产品&#x…

ThinkPHP一对一关联模型的运用(ORM)

一、序言 最近在写ThinkPHP关联模型的时候一些用法总忘&#xff0c;我就想通过写博客的方式复习和整理下一些用法。 具体版本&#xff1a; topthink/framework&#xff1a;6.1.4topthink/think-orm&#xff1a;2.0.61 二、实例应用 1、一对一关联 1.1、我先设计了两张表&#x…

[SWPU2019]Web1

上来看到两个功能&#xff0c;登录和注册&#xff0c;看到登录框直接sqlmap嗦一下 失败 注册admin显示被注册&#xff0c;那就注册一个账密都为aaa 登录进来发现两个功能点 发了一个广告却显示代管理确认&#xff0c;这里肯定没有管理员&#xff0c;所以我们得想办法自己上去a…

铲屎官的必备好物——希喂、352、米家养宠空气净化器分享

对于每一位深爱着家中萌宠的铲屎官而言&#xff0c;无尽的温情往往也伴随着日常生活中的小烦恼。那些不经意间飘散在空气中的毛发&#xff0c;偶尔缠绕在鼻腔或口腔中的细微触感&#xff0c;以及偶尔袭来的不明异味&#xff0c;都是与宠物共度的日子里不可或缺的一部分。幸好随…

聊聊RNNLSTM

RNN 用于解决输入数据为&#xff0c;序列到序列(时间序列)数据&#xff0c;不能在传统的前馈神经网络(FNN)很好应用的问题。时间序列数据是指在不同时间点上收集到的数据&#xff0c;这类数据反映了某一事物、现象等随时间的变化状态或程度&#xff0c;即输入内容的上下文关联…

基于Orangepi全志H616开发嵌入式数据库——SQLite

目录 一、SQLite数据库 1.1 SQLite 的特点&#xff1a; 1.2 SQLite 的使用场景&#xff1a; 1.3 SQLite数据库与传统MySQL数据库的区别&#xff1a; 二、SQLite数据库安装 2.1 SQLite数据库安装方式一&#xff1a; 2.2 SQlite数据库安装方式二&#xff1a; 三、SQLite数…

Nacos适配达梦数据库并制作镜像

背景&#xff1a;因项目需要信创&#xff0c;需将原本的mysql数据库&#xff0c;改成达梦数据库 一、部署达梦数据库 1.1 部署达梦数据库服务 可参考&#xff1a;Docker安装达梦数据库_达梦数据库docker镜像-CSDN博客 1.2 创建nacos数据库 create user SAFE_NACOS identifi…

放大电路总结

补充: 只有直流移动时才有Rbe动态等效电阻 从RsUs看进去,实际上不管接了什么东西都能够看成是一个Ri(输入电阻) Ri Ui/Ii Rb//Rbe Ui/Us Ri/(RiRs) Aus (Uo/Ui)*(Ui/Us) Au *Ri/(RiRs) 当前面是一个电压源的信号 我们就需要输入电阻更大 Ro--->输出电阻--->将…

VSCode+git的gitee仓库搭建

​ 在此之前你已经在gitee创建好了账号&#xff0c;并新建了一个仓库。 1. 安装 Visual Studio Code Visual Studio Code 是编辑 Markdown 和站点配置文件的基础&#xff0c;以下将其简称为 VSCode&#xff0c;你可以在它的 官方网站 下载到它。 如若不理解各个版本之间的区别…

【C++ —— 用一棵红黑树同时封装出map和set】

C —— 用一棵红黑树同时封装出map和set 总览RBTreeMyMapMySet 红黑树源代码红黑树模板参数的控制模板参数中仿函数的增加迭代器模拟1. 迭代器的定义和结构2. 迭代器的操作符重载 set模拟map模拟代码红黑树的代码set的代码map的代码 总览 RBTree enum Colour {RED,BLACK };//…