Java优先级队列(堆)

🐵本篇文章将对优先级队列(堆)的相关知识进行讲解


一、优先级队列

队列是一种“先入先出”的数据结构,但有时操作的数据带有优先级,需要优先处理,这时普通的队列就不能满足需求。比如:在排队取票时,往往会有老人优先、退伍军人优先等。这就可以理解为优先级队列的一种体现

优先级队列的底层是由一种叫的数据结构实现的

二、堆

2.1 什么是堆

将元素按照完全二叉树的顺序存储方式存储到一维数组中,堆分为大根堆小根堆

如上图,如果满足每一个父亲节点的值都大于其左右孩子结点的值,则称为大根堆

如上图,如果满足每一个父亲节点的值都小于其左右孩子结点的值,则称为小根堆

2.2 堆的创建

堆的向下调整

public class Heap {public int[] elem;public int usedSize; //记录数组中元素的个数public Heap() {this.elem = new int[10]; //构造方法:数组的初始容量为10}public void initElem(int[] array) { //初始化elem数组for (int i = 0; i < elem.length; i++) {elem[i] = array[i];usedSize++;}}
}

以大根堆为例,如果一棵完全二叉树是大根堆,则其每一课子树也都是大根堆,定义一个parent表示最后一棵子树的根结点的下标,再定义一个child表示parent结点的左孩子的下标

每调整完一个子树后就让parent--,去调整下一棵子树

那么该如何用代码表示parent和child的下标:首先是parent,usedSize表示数组中元素的个数,usedSize - 1就是最后一个结点的下标,根据二叉树的性质,让其减1再除2就是要得到的最后一个子树的根结点下标,表示为(usedSize -1 - 1)/ 2,child同样也是根据二叉树的性质,child = 2 * parent + 1

得到parent和child后,开始对第一个子树进行调整:首先要让child表示为左右孩子较大值结点的下标

    public void creatBigHeap() { //创建大根堆for (int parent = (usedSize - 1 - 1) / 2; parent >= 0 ; parent--) {siftDown(parent, usedSize);}}public void siftDown(int parent, int end) { //向下调整int child = 2 * parent + 1;if (child + 1 < usedSize && elem[child] < elem[child + 1]) {child++;}...}

接下来就是比较elem[parent]elem[child],如果孩子结点大于其父亲结点则进行交换,交换完后,让parent = child,child = 2 * parent + 1,继续向下调整

如上图,此时说明这个子树已经调整完毕,当在调整{19, 34}这个树时当parent = 5、child = 11时,这个树就调整完了,所以可以用代码写一个循环,循环条件为child < usedSize

    public void siftDown(int parent, int end) {int child = 2 * parent + 1;while(child < end) {if (child + 1 < usedSize && elem[child] < elem[child + 1]) {child++;}if (elem[child] > elem[parent]) {swap(child, parent);parent = child;child = 2 * parent + 1;} else {break;}}}private void swap(int child, int parent) {int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;}

那么整个大根堆就创建完了,完整代码如下:

public class Heap {public int[] elem;public int usedSize; //记录数组中元素的个数public Heap() {this.elem = new int[10]; //构造方法:数组的初始容量为10}public void initElem(int[] array) { //初始化elem数组for (int i = 0; i < elem.length; i++) {elem[i] = array[i];usedSize++;}}public void creatBigHeap() { //时间复杂度为O(n)for (int parent = (usedSize - 1 - 1) / 2; parent >= 0 ; parent--) {siftDown(parent, usedSize);}}public void siftDown(int parent, int end) {int child = 2 * parent + 1;while(child < end) {if (child + 1 < usedSize && elem[child] < elem[child + 1]) {child++;}if (elem[child] > elem[parent]) {swap(child, parent);parent = child;child = 2 * parent + 1;} else {break;}}}private void swap(int child, int parent) {int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;}
}

堆的向上调整和向下调整类似

    public void siftUp(int child) {int parent = (child - 1) / 2;while(parent > 0) {if (child + 1 < usedSize && elem[child] < elem[child + 1]) {child++;}if (elem[child] > elem[parent]) {swap(child, parent);child = parent;parent = (child - 1) / 2;} else {break;}}}

2.3 堆的插入与删除

堆的插入可以将元素放到数组的末尾,然后可以通过向上调整将其调整为大根堆或小根堆

    public void offer(int key) {if (isFull()) { //判断是否需要扩容elem = Arrays.copyOf(elem, 2 * usedSize);}elem[usedSize] = key;usedSize++;siftUp(usedSize - 1);}

堆的删除,由于堆顶的元素,所以可以将堆顶的元素和最后一个元素交换,再让usedSize--后将其向下调整为大根堆或小根堆即可

    public int poll() {int tmp = elem[0];swap(0, usedSize - 1);usedSize--;siftDown(0, usedSize);return tmp;}

2.4 堆排序

堆排序就是按照堆的思想排序,假如要将一组数据按照从小到大排序,则先将这组数据创建为大根堆,不建小根堆是因为其不能保证左右孩子也是有序的。以下图为例:

由于是大根堆,所以堆顶元素是最大的,将堆顶元素和最后一个元素交换,交换后再调整为大根堆,此时再将堆顶元素与倒数第二个元素交换,交换后再调整为大根堆,如此循环

    public void heapSort() {int end = usedSize - 1; //此时为最后一个元素的下标while(end > 0) {swap(0, end);siftDown(0, end - 1);//由于交换了0下标,所以只需要从0下标开始向下调整//交换完后end位置不再属于大根堆,所以在end -1处结束调整end--;}}

三、PriorityQueue接口介绍

该接口的底层是一个小根堆,先来介绍在该接口中的几个字段

3.1 构造方法

首先是上述三个基础的构造方法,可以观察到这三个构造方法都调用了另外一个构造方法:

调用不带参数的构造方法,此时数组的大小为初始容量:11

调用第一个带参数的构造方法,此时数组的大小为initalCapacity

第三个构造方法,其参数是一个比较器,接下来简单复习一下比较器(Comparator接口)

class Person {public int age;public String name;public Person(int age, String name) {this.age = age;this.name = name;}
}class Imp implements Comparator<Person> {public int compare(Person p1, Person p2) {return p1.name.compareTo(p2.name); //调用了String类的compareTo方法//前者>后者,返回一个大于0的数//前者<后者,返回一个小于0的数//前者=后者,返回0}
}class Main {public static void main(String[] args) {Person p1 = new Person("Sans", 20);Person p2 = new Person("Frisk", 8);Imp imp = new Imp();System.out.println(imp.compare(p1, p2));}
}

调用第二个带参数的构造方法

那么传比较器作为参数究竟有什么用,接下来通过分析offer方法的源码进行讲解

3.2 接口中的常用方法

boolean offer(E e);

插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度为O(log₂N),如果空间不够就会进行扩容

E peek();

获取优先级最高的元素,即堆顶的元素,如果优先级队列为空,则返回null

E poll();

删除优先级最高的元素并返回,如果优先级队列为空,则返回null,时间复杂度为O(log₂N)

int size();

获取优先级队列中有效元素的个数

void clear();

清空优先级队列

boolean isEmpty();

判断优先级队列是否为空,如果为空,则返回true


🙉以上就是本文关于优先级队列的全部内容,接下来会对排序的相关知识进行讲解

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

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

相关文章

(vue)Module Error (from ./node_modules/eslint-loader/index.js)

(vue)Module Error (from ./node_modules/eslint-loader/index.js) 参考&#xff1a;解决参考

mac安全干净卸载Anaconda3

使用which python显示当前使用的是/Users/username/anaconda3/bin/python 现在想卸载Anaconda&#xff0c;恢复使用mac系统自带的Python 删除隐藏文件目录 rm -rf ~/.anaconda修改~/.bash_profile文件&#xff0c;将anaconda相关删除 也有可能不是~/.bash_profile而是~/.zs…

现代DevOps如何改变软件开发格局

在软件开发的早期&#xff0c;该过程通常是开发人员编写代码&#xff0c;再将其交给质量保证&#xff08;QA&#xff09;进行测试。这种瀑布开发方法可能会导致质量问题和延迟&#xff0c;因为问题是在周期后期发现的。 一、了解DevOps和测试左移 DevOps是Development和Opera…

OCR-free相关论文梳理

引言 通用文档理解&#xff0c;是OCR任务的终极目标。现阶段的OCR各种垂类任务都是通用文档理解任务的子集。这感觉就像我们一下子做不到通用文档理解&#xff0c;退而求其次&#xff0c;先做各种垂类任务。 现阶段&#xff0c;Transformer技术的发展&#xff0c;让通用文档理…

Android App冷启动耗时优化

Android应用启动过程 Android应用启动过程&#xff0c;主要包含app::onCreate及执行前的Application阶段及Activity::onCreate执行之后的Activity阶段&#xff0c;以及两个阶段之间的间隙handleMessage阶段和最终页面渲染上屏完成前数据加载阶段四个区间组成。 具体来看&#x…

SpringBlade error/list SQL 注入漏洞复现

0x01 产品简介 SpringBlade 是一个由商业级项目升级优化而来的 SpringCloud 分布式微服务架构、SpringBoot 单体式微服务架构并存的综合型项目。 0x02 漏洞概述 SpringBlade 框架后台 /api/blade-log/error/list路径存在SQL注入漏洞,攻击者除了可以利用 SQL 注入漏洞获取数…

【SpringBoot】自定义工具类实现Excel数据新建表存入MySQL数据库

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 …

SpringCloudAlibaba 网关gateway整合sentinel日志默认路径修改

SpringCloudAlibaba 网关gateway整合sentinel 实现网关限流熔断 问题提出 今天运维突然告诉我 在服务器上内存满了 原因是nacos日志高达3G,然后将日志文件发给我看了一下之后才发现是gateway整合sentinel使用了默认日志地址导致日志生成地址直接存在与根路径下而且一下存在多…

Explain

Explain EXPLAIN是MySQL提供的一种用于分析SQL查询执行计划的工具&#xff0c;通过它我们可以深入了解数据库如何执行一条SQL语句&#xff0c;以及优化器在选择索引、访问表和排序数据等方面的决策。 我整理了一份思维导图方便更好查看各个参数的意义&#xff0c;红色表示比较…

泛目录站群程序,seo站群系统(川圣SEO)#蜘蛛池

baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? 功能介绍&#xff1a; &#xff08;全新模板 PC、移动端自适应 无限泛二级域名首页&#xff0c;标题增加进制干扰码&#xff0c;关键词进制干…

AJAX 03 XMLHttpRequest、Promise、封装简易版 axios

AJAX 学习 AJAX 3 原理01 XMLHttpRequest① XHR 定义② XHR & axios 关系③ 使用 XHR④ XHR查询参数案例&#xff1a;地区查询&#xff08;URLSearchParams&#xff09;⑤ XHR数据提交 POST 02 PromisePromise 使用Promise - 三种状态案例&#xff1a;使用Promise XHR 获取…

linux sshd_config配置说明

[root01 ssh]# cat sshd_config #######################SSH Base Config################## #######通过OpenSSH工具入xshell连接默认端口 可以改成其他默认是22 PAM 认证过程 1&#xff09;使用者执行/usr/bin/passwd程序&#xff0c;并输入密码。 2&#xff09;passwd开…

【C语言_C语言语句_复习篇】

目录 一、C语言的语句有哪些 1.1 空语句 1.2 表达式语句 1.3 函数调用语句 1.4 复合语句 1.5 控制语句 二、分支语句&#xff08;两种&#xff09; 1.1 if语句 1.1.1 普通分支语句(if、if_else) 1.1.2 嵌套if语句 1.1.3 else嵌套if两种写法的比较 1.1.4 else悬空问题 1.1.…

【读论文】【精读】3D Gaussian Splatting for Real-Time Radiance Field Rendering

文章目录 1. What&#xff1a;2. Why&#xff1a;3. How&#xff1a;3.1 Real-time rendering3.2 Adaptive Control of Gaussians3.3 Differentiable 3D Gaussian splatting 4. Self-thoughts 1. What&#xff1a; What kind of thing is this article going to do (from the a…

普林斯顿算法讲义(三)

原文&#xff1a;普林斯顿大学算法课程 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 4.2 有向图 原文&#xff1a;algs4.cs.princeton.edu/42digraph 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 有向图。 一个有向图&#xff08;或有向图&#xff09;是…

Docker常见指令

1.docker search mysql &#xff1a;从docker镜像仓库搜索和mysql有关的镜像 docker search mysql 2.docker pull mysql &#xff1a;从docker仓库拉取mysql镜像 docker pull mysql 3.docker run mysql &#xff1a;启动mysql镜像 docker run mysql 4.docker ps &#xff…

Spring Boot 中@Scheduled是单线程还是多线程?

在开发Spring Boot应用程序时&#xff0c;定时任务是一项常见的需求。Spring Boot提供了Scheduled注解&#xff0c;可用于将方法标记为定时任务&#xff0c;并在预定的时间间隔内执行。那么Scheduled注解的执行方式是单线程执行&#xff0c;还是多线程执行&#xff1f;Schedule…

GPT-SoVITS开源音色克隆框架的训练与调试

GPT-SoVITS开源框架的报错与调试 遇到的问题解决办法 GPT-SoVITS是一款创新的跨语言音色克隆工具&#xff0c;同时也是一个非常棒的少样本中文声音克隆项目。 它是是一个开源的TTS项目&#xff0c;只需要1分钟的音频文件就可以克隆声音&#xff0c;支持将汉语、英语、日语三种…

HNU计算机系统·汇编进阶

知识回顾&#xff1a; 寻址&#xff1a; 其中&#xff0c;比例因子S&#xff0c;只能是1&#xff0c;2&#xff0c;4&#xff0c;8中的数&#xff0c;这是因为在LEA的独立电路中使用移位寄存器 上节课的补充&#xff1a; mov部分: mov value , %eax mov $value , %eax 第一条…

Day34:安全开发-JavaEE应用反射机制攻击链类对象成员变量方法构造方法

目录 Java-反射-Class对象类获取 Java-反射-Field成员变量类获取 Java-反射-Method成员方法类获取 Java-反射-Constructor构造方法类获取 Java-反射-不安全命令执行&反序列化链构造 思维导图 Java知识点 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;…