【Java数据结构】优先级队列详解(二)

🔒文章目录:

1.❤️❤️前言~🥳🎉🎉🎉

2.PriorityQueue的特性

 3.优先级队列的构造

4.如何控制优先级队列是小堆还是大堆

5.PriorityQueue的方法

6. PriorityQueue的自动扩容方式

7.top-k问题——最小k个数

8.堆排序

9.总结 


1.❤️❤️前言~🥳🎉🎉🎉

Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。

如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的内容感兴趣,记得关注我👀👀以便不错过每一篇精彩。

当然,如果在阅读中发现任何问题或疑问,我非常欢迎你在评论区留言指正🗨️🗨️。让我们共同努力,一起进步!

加油,一起CHIN UP!💪💪

🔗个人主页:E绵绵的博客
📚所属专栏:

1. JAVA知识点专栏

        深入探索JAVA的核心概念与技术细节

2.JAVA题目练习

        实战演练,巩固JAVA编程技能

3.c语言知识点专栏

        揭示c语言的底层逻辑与高级特性

4.c语言题目练习

        挑战自我,提升c语言编程能力

📘 持续更新中,敬请期待❤️❤️

 

2.PriorityQueue的特性

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


 

该图是priorityQueue的父类和接口,了解一下就行了。

关于PriorityQueue的使用要注意:

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

import java.util.PriorityQueue;

2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException异常。这个等会会详细介绍。

3. 优先级队列不能插入null对象,否则会抛出NullPointerException(普通队列和栈都能插入null对象,优先级队列不行)

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

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

 3.优先级队列的构造


👉无参构造法 底层数组默认容量是11

        Queue<Integer> priorityQueue1 = new PriorityQueue<>();

 👉整形数据作为参数, 设置化底层数组容量

        Queue<Integer> priorityQueue2 = new PriorityQueue<>(10);

👉用一个集合来创建优先级队列,该集合中的数据全放到优先级队列中(创建后原本的顺序可能会改变,因为它是大根堆或小根堆)

PriorityQueue(Collection<? extends E> c)

这个构造函数接受的是一个Collection类型的参数,因此可以传入任何实现了Collection接口的类的对象。

并且因为该构造函数还使用了<? extends E>,它表示传递给构造函数的集合c中的<元素类型>必须是E或E的子类。

以下是实例:

 Queue<Integer>  queue=new ArrayDeque<>();queue.offer(8);queue.offer(7);queue.offer(9);PriorityQueue<Integer> priorityQueue=new PriorityQueue<>(queue);System.out.println(priorityQueue.size());System.out.println(priorityQueue.peek());


4.如何控制优先级队列是小堆还是大堆

默认情况下,我们用以上三种构造方法创建的PriorityQueue队列是小堆,具体我们看源码。

 

当我们执行之前讲过的三种任意一种构造方法时,comparator都是null,所以在执行之后的操作必会执行类似的siftupComparable方法,该方法源码如下

 

由此可知当我们priorityqueue存储的是包装类如Integer时,其默认为小根堆。


而当我们用自定义类比较时,因为如上源码用了compareTo去比较,该方法是comparable类的方法,如果该自定义类没有实施comparable接口,重写compareTo方法去比较该类 ,则会出现异常报错。(包装类本身重写了compareTo方法)

以下是正确做法:

public class Test4 {public static void main(String[] args) {PriorityQueue<Method> priorityQueue=new PriorityQueue<>();priorityQueue.offer(new Method(4));priorityQueue.offer(new Method(8));priorityQueue.offer(new Method(9));System.out.println(priorityQueue.peek().size);}
}class  Method implements Comparable<Method>{public int size;@Overridepublic int compareTo(Method o) {return o.size-this.size;}public Method(int size) {this.size = size;}}

  

由结果可以发现创建了大根堆,这是因为重写的compareTo方法中this类的size如果大于o类的size,则返回负数。导致为大根堆(具体细节观察源码可以发现,这里不细讲) 

所以我们发现了一个很重要的规律:对于重写的方法,如果前面的类大于后面的类(this一般看作前面的类),该方法返回出正数,则为小根堆。否则为大根堆。


除此之外这里还有第四种构造方法,也是最为重要的,这个需要我们自己创建一个比较类。

 

由该构造方法可知,我们要接收一个类且该类必须实施了comparator接口,该接口的泛型参数必须为E本身或者E的父类(E为priorityQueue创建出的对象的泛型参数)


由上可知,在构造完后,comparator就不为null,所以执行siftupusingComparator方法,其源码如下:

此时内部我们就执行了compare方法,comparator接受的是我们之前创建的比较类,所以执行比较类中重写的compare方法,我们就能通过该方法去控制是大根堆还是小根堆 。

以下是正确做法:

(堆内部存储着包装类)

public class Test3 {public static void main(String[] args) {PriorityQueue<Integer> priorityQueue=new PriorityQueue<>(new Int());priorityQueue.offer(4);priorityQueue.offer(8);priorityQueue.offer(9);System.out.println(priorityQueue.peek());}
}class  Int implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return  o2-o1;}}

 根据规律得出 o1如果大于o2,则返回负数,所以是大根堆,打印出9

 


(堆内部存储着自定义类)

​
public class Test5 {public static void main(String[] args) {PriorityQueue<Method1> priorityQueue=new PriorityQueue<>(new Meth());priorityQueue.offer(new Method1(4));priorityQueue.offer(new Method1(8));priorityQueue.offer(new Method1(9));System.out.println(priorityQueue.peek().size);}
}
class  Method1 {public int size;public Method1(int size) {this.size = size;}
}
class  Meth implements Comparator<Method1> {@Overridepublic int compare(Method1 o1, Method1 o2) {return  o1.size-o2.size;}
}​

  根据规律得出 o1如果大于o2,则返回正数,所以是小根堆,打印出4.

 


现在来个总结:

1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法,控制其为大根堆或小根堆。当插入包装类时默认就是小根堆改变不了。

2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象或包装类对象时,可以提供一个比较器类,让该类实现 Comparator接口并覆写compare方法,从而控制该堆是大堆还是小堆。

5.PriorityQueue的方法

因为是优先级队列,所以它的这些方法名称自然跟普通队列一模一样,只是本质是不一样的。(对于这些本质我们在上一篇文章中模拟过了,了解的很清楚了就不多说了)

需要记住的是:

offer不能输入null进去,否则会报错。

当队列为空时,peek和poll都会返回null 。

public class Test2 {public static void main(String[] args) {PriorityQueue<Integer> priorityQueue=new PriorityQueue<>();priorityQueue.offer(4);priorityQueue.offer(8);priorityQueue.offer(9);System.out.println(priorityQueue.peek());priorityQueue.poll();System.out.println(priorityQueue.size());System.out.println(priorityQueue.isEmpty());priorityQueue.clear();System.out.println(priorityQueue.isEmpty());}
}

 

6. PriorityQueue的自动扩容方式

这个只需了解就行,无需详细记住,知道它能自动扩容就ok了。

 

7.top-k问题——最小k个数

📌题目描述 

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。


 📋题目思路

  1. 创建优先队列(PriorityQueue):使用PriorityQueue<Integer>,这是一个自调整大小的最小堆数据结构。堆的特性保证了插入元素时总是将当前最小的元素添加到队列顶部。

  2. 遍历数组并插入优先队列:使用for循环遍历输入数组arr,将每个元素arr[i]添加到priorityQueue中。由于优先队列自动维护最小值,所以每次添加都会替换队列顶部(也就是当前最小值)。

  3. 构建结果数组:当遍历完整个输入数组后,priorityQueue中应该包含了前k个最小元素。再次使用for循环,从priorityQueue中取出k个元素并放入新数组arr1。因为poll()方法会返回并移除队列中的最小元素,所以这里实际上是按顺序获取最小元素。

  4. 返回结果:完成arr1的构建后,返回这个包含前k小元素的数组。

⏳题目代码

class Solution {public int[] smallestK(int[] arr, int k) {PriorityQueue<Integer> priorityQueue=new PriorityQueue<>();for (int i = 0; i <arr.length ; i++) {priorityQueue.offer(arr[i]);}int[]  arr1=new int[k];for (int i = 0; i <k ; i++) {arr1[i] =  priorityQueue.poll();}return  arr1;}
}

题目链接:最小k个数 

8.堆排序

  我们通过堆这种数据结构去排序数组 就叫堆排序。这里简单说一下,不过多牵扯,代码示    例如下:

public class Sort {public static void main(String[] args) {int[] arr={0,-3,6,9,65,12,43,4,36,21,-9};PriorityQueue<Integer> priorityQueue=new PriorityQueue<>(new Int());for (int i = 0; i <arr.length ; i++) {priorityQueue.offer(arr[i]);}for (int i = 0; i <arr.length ; i++) {arr[i]= priorityQueue.poll();}System.out.println(Arrays.toString(arr));}}

这里我们用堆排序将数组从大往小排。对于上述代码大家应该都能看懂,就不多说了,看下对于堆的实际应用就行了。

9.总结 

所以这篇文章我们就把堆(priorityqueue)的使用讲述清楚了,堆也就此完结了,花了两篇文章去讲解。之后将给大家带来排序的讲解。在此,我们诚挚地邀请各位大佬们为我们点赞、关注,并在评论区留下您宝贵的意见与建议。让我们共同学习,共同进步,为知识的海洋增添更多宝贵的财富!🎉🎉🎉❤️❤️💕💕🥳👏👏👏

 

 

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

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

相关文章

6.13作业

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口标题this->setWindowTitle("QQ");//设置窗口图标this->setWindowIcon(QIcon("C:/Users/…

鸿蒙轻内核A核源码分析系列七 进程管理 (1)

本文开始继续分析OpenHarmony LiteOS-A内核的源代码&#xff0c;接下来会分析进程和任务管理模块。本文中所涉及的源码&#xff0c;以OpenHarmony LiteOS-A内核为例&#xff0c;均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_a 获取。如果涉及开发板&#xff…

spring中IOC容器创建流程

跳转参考地址&#xff1a;https://wuliqun.cn/details?pps53

【安装笔记-20240613-Linux-在 OpenWrt 的 LuCI界面支持命令行调试】

安装笔记-系列文章目录 安装笔记-20240613-Linux-在 OpenWrt 的 LuCI界面支持命令行调试 文章目录 安装笔记-系列文章目录安装笔记-20240613-Linux-在 OpenWrt 的 LuCI界面支持命令行调试 前言一、软件介绍名称&#xff1a;ttyd主页官方介绍特点 二、安装步骤测试版本&#xf…

两种典型的嵌入式系统架构模式

大多数嵌入式系统都具备实时特征&#xff0c;那么&#xff0c;这种嵌入式系统的典型架构可概括为两种模式&#xff0c;即层次化模式架构和递归模式架构。 1.层次化模式架构 为了达到概念一致性&#xff0c;许多系统通过层次化的方法进行搭建。这样做的结果是&#xff1a;位于高…

Chisel入门——在windows系统下部署Chisel环境并点亮FPGA小灯等实验

Chisel入门——在windows系统下部署Chisel环境并点亮FPGA小灯等实验 一、chisel简介二、vscode搭建scala开发环境2.1 安装Scala官方插件2.2 java版本&#xff08;本人用的是jdk18&#xff09;2.3 下载Scala Windows版本的二进制文件2.4 配置环境变量2.5 scala测试2.6 vscode运行…

axure制作菜单下拉、隐藏、点击选中效果

在高保真原型中&#xff0c;制作导航栏菜单时&#xff0c;需要达到点击下拉按钮&#xff0c;子菜单自动弹出&#xff0c;点击其中一个子菜单项可栏目变为选中状态且跳转到对应的子页面。制作材料可以从antdesign中去下载&#xff0c;以下述网络配置菜单为例。在箭头处添加互动效…

RedHat8.4离线升级内核(漏洞编号CVE-2024-1086)

一、背景 针对Linux内核提取权限漏洞 (漏洞编号CVE-2024-1086&#xff09;&#xff0c;整理离线环境的修复方案。本文以离线修复方案为主进行说明&#xff0c;第八章对在线修复方案进行说明。 (一) 漏洞简介 近日&#xff0c;绿盟科技CERT监测网上有研究员公开披露了一个Lin…

SpringBoot Vue Bootstrap 旅游管理系统

SpringBoot Vue 旅游管理系统源码&#xff0c;附带环境安装&#xff0c;运行说明 源码地址 开发环境 jdk1.8,mysql8,nodejs16,navicat,idea 使用技术springboot mybatis vue bootstrap 部分功能截图预览

【SQLAlChemy】常见的数据类型有哪些,Column可选的参数有哪些呢?

常见数据类型与Column参数 常见类型 Integer&#xff1a;整数类型&#xff0c;对应数据库的 int 类型。Float&#xff1a;浮点数类型&#xff0c;对应数据库的 float 类型。它占用 32 位空间。Double&#xff1a;双精度浮点数类型&#xff0c;对应数据库的 double 类型&#…

【CS.PL】Lua 编程之道: 基础语法和数据类型 - 进度16%

2 初级阶段 —— 基础语法和数据类型 文章目录 2 初级阶段 —— 基础语法和数据类型2.0 关键字(keywords) &#x1f525;2.1 注释与标识符2.1.1 注释2.1.2 标识符 2.2 变量与赋值2.2.1 所有变量默认是全局变量 ≠ local, 有一个例外2.2.2 local变量是局部变量, 以end作为边界2.…

创建节约机关怎样向媒体投稿报道宣传?

创建节约机关并向媒体投稿报道宣传是一项重要的工作&#xff0c;它不仅能够提升机关的形象&#xff0c;还能促进社会各界对节约型社会的认识和支持。 作为一名新晋信息宣传员,初入职场的我满腔热血,怀揣着用文字传递价值的理想,却在投稿的道路上屡遭波折。面对每月的宣传任务,我…

表 达式树

》》》可以借助 LINQPad工具 using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using System.Transactions;namespace EFDemo {public cla…

vite工程化搭建vue项目之自动按需导入

背景 当我们在使用vue3组合式开发的时候&#xff0c;大多数情况下我们的代码可能是这样的 <script setup lang"ts"> import { ref, reactive, toRefs, onMounted, computed } from vue; defineProps({}); </script><template><div></di…

共模信号与差模信号

差模信号又称串模信号&#xff0c;指的是两根线之间的信号差值&#xff1b;而共模信号又称对地信号&#xff0c;指的是两根线分别对地的信号。 差模信号&#xff1a;大小相等&#xff0c;方向相反的信号。共模信号&#xff1a;大小相等&#xff0c;方向相同的信号。 对于两输…

python的np.array()函数

1、创建数组 2、 与矩阵相关的函数 3、与排序相关的函数 4、 一元计算函数 5、 多元计算函数 6、 与文件读写相关的函数 7、与数组形状、属性相关的函数 8、 常用计算函数 9、 数组选取:切片和索引 10、np.random相关函数 Numpy常用的20个函数 一…

京准电钟 | 对比GPS,北斗卫星授时的场景有哪些?

京准电钟 | 对比GPS&#xff0c;北斗卫星授时的场景有哪些&#xff1f; 京准电钟 | 对比GPS&#xff0c;北斗卫星授时的场景有哪些&#xff1f; 对比国外的GPS&#xff0c;我国北斗卫星授时由于其高精度和稳定性&#xff0c;在各个领域都有广泛的应用场景。 以下是一些单北斗卫…

为什么需要负样本

假如我们只有正样本&#xff0c;模型在最开始训练的时候都是错误的&#xff0c;随着模型的迭代&#xff0c;准确率逐渐从0到1&#xff0c;最终将所有的样本都判别成正样本&#xff0c;也就是都在线的上方。 但真实的场景中有正有负&#xff0c;例如我们要做一个猫狗分类器&…

WINUI——CommunityToolkit.Mvvm Messenger接收消息时报错:Cannot access a disposed object.

背景 WINUI开发时使用CommunityToolkit.Mvvm的Messemger让UI展示一些信息时出现错误&#xff1a; System.ObjectDisposedException:“Cannot access a disposed object. ObjectDisposed_ObjectName_Name” 详细见下述截图&#xff1a; 开发环境 WIN11 WINUI&#xff13; …

如何在3天内开发一个鸿蒙app

华为鸿蒙操作系统&#xff08;HarmonyOS&#xff09;自2.0版本正式上线以来&#xff0c;在短时间内就部署超过了2亿台设备&#xff0c;纵观全球操作系统的发展史&#xff0c;也是十分罕见的。与其他手机操作系统不同&#xff0c;HarmonyOS自诞生之日起&#xff0c;就是一款面向…