java优先级队列(堆)详解

一、优先级概念

什么是优先级:比如女士优先,个子低的优先排到前面去,有一部分数据具备优先级,要以优先级的顺序将顺序存储起来。

前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列

priorityQueue是二叉树的完全二叉树,只不过是用数组来进行顺序存储

PriorityQueue底层使用了堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整。

二、堆的概念

所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足:Ki 且 Ki= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

性质:

堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

小根堆:根节点的大小小于孩子节点

大根堆:根节点的大小大于孩子节点

三、堆的存储方式

从堆的概念可知,堆是一棵完全二叉树,因此可以层序的规则采用顺序的方式来高效存储,

完全二叉树:数组的每一个位置被充分使用    

一般二叉树:有的位置被浪费掉没有存储值

所以对于非完全二叉树,则不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节点,就会导致空间利用率比较低。

四、堆的创建与方法实现

import java.util.Arrays;public class TestHeap {public int[] elem;public int usedSize;public TestHeap(){this.elem = new int[10];}public void init(int[] array){for(int i = 0;i<array.length;i++){elem[i] = array[i];usedSize++;}}//把elem数组当中的数据 调整为大根堆public void createHeap(){int size = usedSize;for(int parent = (size-1-1)/2;parent>=0;parent--){siftDown(parent,size);}}private void swap(int i,int j){int tmp = elem[i];elem[i] = elem[j];elem[j] = tmp;}//每棵子树向下调整  知父亲求孩子public void siftDown(int parent,int end){int child = 2*parent+1;while(child<end){if(child+1<end&&elem[child]<elem[child+1]){//找到大的             child++;}//chile下标就是左右孩子最大值if(elem[child]>elem[parent]){swap(child,parent);parent = child;child = 2*parent+1;}else{break;}}}//调整为小根堆public void siftDown2(int parent,int end){int child = 2*parent+1;while(child<end){if(child+1<end&&elem[child]>elem[child+1]){//找出最小child++;}//chile下标就是左右孩子最大值if(elem[child]<elem[parent]){swap(child,parent);parent = child;child = 2*parent+1;}else{break;}}}//插入public void offer(int val){if(isFull()){elem = Arrays.copyOf(elem,2*elem.length);}elem[usedSize] = val;usedSize++;siftUp(usedSize-1);}//向上调整成大根堆,知孩子求父亲public void siftUp(int child){int parent = (child-1)/2;while(parent>=0){if(elem[child]>elem[parent]){swap(child,parent);child = parent;parent = (child-1)/2;}else{break;}}}//向上调整复杂度O(N*logN)public boolean isFull(){return usedSize==elem.length;}//删除第一个节点 将0下标与最后一个节点交换,再向下调整public int poll(){if(isEmpty()){return -1;}int old = elem[0];swap(0,usedSize-1);usedSize--;siftDown(0,usedSize);return old;}public boolean isEmpty(){return usedSize==0;}//数组排序,从小往大排,建立大根堆,从大往小排建立小根堆public void heapSort(){int endIndex = usedSize-1;//O(N)while(endIndex>0){swap(0,endIndex);siftDown(0,endIndex);//调整成大根堆O(logN)endIndex--;}//O(N*logN)}}

对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成堆呢?

调整大根堆方法:从整棵树的最后一棵子树开始调整,每次让根节点与左右孩子比较,如果根节点比左右孩子的最大值都小,就交换根节点和孩子最大值。(小根堆同理)

上图就是大根堆

向下调整时间复杂度:约为N

Tn = 2^0*(h-1)+2^1*(h-2)+...+2^(h-2)*1+2^(h-1)*0
2Tn = 2^1*(h-1)+2^2*(h-2)+...+2^(h-1)*1
两式错位相减Tn = -2^0(h-1)+2^1+2^2+.....+2^(h-1)=-h-1+2^h
h = log以2为底(N+1)
Tn = -log(N+1)-1+N+1 = N-log(N+1)
n越来越大Tn约等于N

向上调整时间复杂度为N*logN

五、PriorityQueue常用接口介绍

1、优先级队列的构造(无构造器)

构造器功能介绍
PriorityQueue()创建一个空的优先级队列,默认容量是11
PriorityQueue(int initialCapacity)创建一个初始容量为initialCapacity的优先级队列,注意: initialCapacity不能小于1,否则会抛IllegalArgumentException异 常
PriorityQueue(Collection<? extends E> c)用一个集合来创建优先级队列
    public static void main(String[] args) {//堆是队列实现的,叫优先级队列,数组实现PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();priorityQueue.offer(12);priorityQueue.offer(5);priorityQueue.offer(57);System.out.println(priorityQueue.peek());//结果是5 所以默认是小根堆,也可以改为大根堆,以后讲Queue<Integer> queue = new PriorityQueue<>();//PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的PriorityBlockingQueue<Integer> priorityBlockingQueue = new PriorityBlockingQueue<>();//多线程下推荐使用}

2、 功能

函数名功能介绍
boolean offer(E e)插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度,注意:空间不够时候会进行扩容

E peek()

获取优先级最高的元素,如果优先级队列为空,返回null
E poll()移除优先级最高的元素并返回,如果优先级队列为空,返回null
int size()获取有效元素的个数

void clear()

清空
boolean isEmpty()检测优先级队列是否为空,空返回true

offer功能 

 

给比较器 

 未给比较器

  将key强转为Comparable,所以需要实现Comparable接口,未实现就会出现类型转换异常

比如:如果创建student类的堆,如果未实现接口就会抛出异常

compareTo可以实现大堆小堆的转换

比较器

默认情况下,PriorityQueue队列是小堆,如果需要大堆需要用户提供比较器

提供比较器构造功能介绍
public PriorityQueue(Comparator<? super E> comparator)
可以改为大堆创建
PriorityQueue(int initialCapacity,              Comparator<? super E> comparator)
可以大堆创建初始容量为initialCapacity的优先级队列
class IntCmp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);//小根堆,如果o1和o2互换就是大根堆}
}

注意:

1、使用时必须导入PriorityQueue所在的包

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

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

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

5. 插入和删除元素的时间复杂度为

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

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

top-k:最小的k个数 

 public static int[] smallestK(int[] arr,int k){PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();for (int i = 0; i < arr.length; i++) {priorityQueue.offer(arr[i]);//时间复杂度NlogN}int[] tmp = new int[k];for (int i = 0;i<k;i++){int val = priorityQueue.poll();//时间复杂度k*logNtmp[i] = val;}//整个时间复杂度是(N+k)logN,不是真的top-k的解法return tmp;}

最小的k个数->建立大小为k的大根堆

最大的k个数->建立大小为k的小根堆 

 class IntCmp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o2.compareTo(o1);//大根堆,如果o1和o2互换就是小根堆}
}
public static int[] smallestK2(int[] arr,int k){int[] tmp = new int[k];if(k==0){return tmp;}PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new IntCmp());//大小为k的大根堆for (int i = 0; i < k; i++) {maxHeap.offer(arr[i]);//K*logK}//遍历剩下的元素for (int i = k;i<arr.length;i++){int val = maxHeap.peek();if(val>arr[i]){maxHeap.poll();maxHeap.offer(arr[i]);}}//(N-K)*logKtmp = new int[k];for (int i = 0;i<k;i++){tmp[i] = maxHeap.poll();//时间复杂度k*logN}return tmp;
//时间复杂度N*logK}

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

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

相关文章

Java:String类

目录 1.String类的重要性2.String对象的比较2.1 比较是否引用同一个对象2.2 boolean equals(Object anObject) 方法&#xff1a;按照字典序比较2.3int compareTo(String s)方法: 按照字典序进行比较2.4 boolean equalsIgnoreCase(Object anObject)方法&#xff1a;忽略大小写的…

word批量修改表格样式

利用宏&#xff0c;批量选中表格&#xff0c;然后利用段落和表设计来操作。 利用宏&#xff0c;批量选中表格&#xff0c;参考百度安全验证段落&#xff0c;表格里面的内容有空格&#xff0c;应该是有缩进&#xff0c;在段落中去掉缩进&#xff0c;即缩进-特殊&#xff0c;选择…

node的事件循环

异步同步啥的就不多说了&#xff0c;直接看node中有哪些是异步 其中灰色部分和操作系统有很大的关系&#xff0c;就不多说了&#xff0c;其中定时器属于timers队列&#xff0c;I/O操作属于poll队列&#xff0c;setImmediate属于check队列&#xff0c;其中nextTick和promise不属…

【Java IO】那字节流和字符流有什么区别?

&#x1f331;以贴近现实的【面试官面试】形式涵盖大部分Java程序员需要掌握的后端知识、面试问题&#xff0c;系列博客收录在我开源的JavaGetOffer中&#xff0c;会一直完善下去&#xff0c;希望收到大家的 ⭐️ Star ⭐️支持&#xff0c;这是我创作的最大动力&#xff1a; h…

2024团体程序设计天梯赛L1-101 别再来这么多猫娘了!

题目链接L1-101 别再来这么多猫娘了&#xff01; #include<iostream> #include<stdio.h> #include<string.h> #include<string> #include<algorithm> using namespace std; string s[105], text; int n, k, ans, a[5005];int main() { // ios::s…

第21天:信息打点-公众号服务Github监控供应链网盘泄漏证书图标邮箱资产

第二十一天 一、开发泄漏-Github监控 1.短期查看 1.密码搜索 根据攻击目标的域名在GitHub上进行搜索密码&#xff0c;如果目标网站的文件与搜索到的源码相关&#xff0c;那就可以联想目标网站是否使用这套源码进行开发 原理就是开发者在上传文件的时候忘记更改敏感文件或者…

利用FFmpeg 转换课程vtt 字幕到 srt字幕

字幕转换工具 经常学习udemy 视频课程的&#xff0c;可能知道&#xff0c;从网络下载的udemy 课程文件里面有时候字幕是vtt 格式的&#xff0c;有时候想导入到百度网盘里面&#xff0c;怎奈百度网盘&#xff0c;不支持vtt 字幕格式。有字幕的时候&#xff0c;会比较好多了。既可…

【机器学习】《ChatGPT速通手册》笔记

文章目录 第0章 前言第1章 ChatGPT的由来&#xff08;一&#xff09;自然语言处理任务&#xff08;二&#xff09;ChatGPT所用数据数据大小&#xff08;三&#xff09;ChatGPT的神经网络模型有175亿个参数&#xff08;四&#xff09;模型压缩 方案 第2章 ChatGPT页面功能介绍&a…

日期相关的题目

日期相关的题目 1. 计算日期到天数转换2. 日期累加3. 打印日期4. 日期差值 1. 计算日期到天数转换 输出示例: 思路&#xff1a;计算前n-1个月的天数在加上这个月的天数。 #include <iostream> using namespace std;int main() {int year, month, day;cin >> yea…

llama2 与 llama3比较

Llama 3 刚刚在4月18号推出&#xff0c;距 Llama 2 发布正好 9 个月。它已经可以在 Meta 网站上进行聊天&#xff0c;可以从 Huggingface 以 safetensors 或 GGUF 格式下载。 llama 2 与 llama3 比较 1. 模型输出&#xff08;model output&#xff09; llama 2 输出只能是文本…

const成员函数 以及 取地址及const取地址操作符重载

目录 const成员函数 结论&#xff1a; 取地址及const取地址操作符重载 const成员函数 将const 修饰的 “ 成员函数 ” 称之为 const成员函数 &#xff0c; const 修饰类成员函数&#xff0c;实际修饰该成员函数的&#xff08;*this&#xff09; &#xff0c;表明在该成员函数…

网络原理-IP协议

一、IP协议报头 版本号:用来表示IP协议的版本,现在常用的IP协议有两个版本,IPv4和IPv6&#xff0c;其他版本可能只存在于实验室中&#xff0c;并没有被广泛的使用。 首部长度:用来表示IP报头的长度,因为存在"选项"字段&#xff0c;所以IP报头是可变长的,此处单位为4…

日期类的实现

目录 Date.h Test.cpp 测试代码Test.cpp 日期类的实现 代码分享 Date.h #pragma once #include<iostream> using namespace std; #include<assert.h>class Date {//友元函数声明friend ostream& operator<<(ostream& out, Date& d);friend…

[渗透测试学习] Headless-HackTheBox

Headless-HackTheBox 信息搜集 使用nmap扫描一下 nmap -sV -sC -v --min-rate 1000 10.10.11.8可以发现5000端口是开放的,继续扫一下目录 访问/dashboard发现只有admin才可以,我们注意到cookie值为JWT加密,拿到揭秘网站验证下猜想 cookie为user用户,那么我们要想访问必须…

[阅读笔记29][AgentStudio]A Toolkit for Building General Virtual Agents

这篇论文是24年3月提交的&#xff0c;提出了一个用于agent开发的全流程工具包。 作者提到目前agent开发主要有两个阻碍&#xff0c;一个是缺乏软件基础&#xff0c;另一个是缺乏在真实世界场景中进行评估。针对这两个阻碍&#xff0c;作者涉及了一个开发工具包&#xff0c;包括…

[已解决]react打包部署

react打包部署 问题 npm install 命令无反应 思路 换成 yarn install 安装完hadoop的环境后&#xff0c;使用node的yarn会报错&#xff1a; 我们在cmd使用where yarn&#xff0c;如下&#xff1a; 看你想保留哪一个&#xff0c;我平时node用的多&#xff0c;就把hadoop的y…

项目小游戏-贪吃蛇

目录 1.游戏开始 - GameStart 1.1cmd命令窗口 调节窗口命令 ​编辑更改窗口命名 ​编辑 1.2 Win32 API win32 API 的介绍: ​编辑 获取控制台坐标COORD 获取控制台句柄: 获取缓冲台光标信息: 获取虚拟键位: 本地初始化 setlocale(); 游戏开始的具体实现&#xff1a…

使用AOP切面做防止用户重复提交功能

在我们的项目中&#xff0c;需要考虑到有时候因为网络原因或者其他原因用户对同一个接口进行同一批数据的重复性操作&#xff0c;如果不做这样的处理很可能会在数据库中添加多条同样的数据。 我们可以通过使用aop来解决这样的问题&#xff0c;接下来看看具体怎么做吧~ 自定义…

网络原理-UDP和TCP

在传输层中有两个非常重要的协议&#xff0c;UDP和TCP&#xff0c;现在就来研究一下这两个协议。 UDP 报文格式 我们观察可以发现&#xff0c;里面UDP报文长度为2个字节&#xff0c;那么是多少呢&#xff1f;我们需要快速反应如下固定字节数据类型的取值范围&#xff1a; 字…

Jenkins服务器IP更换,Jenkins URL地址更换

服务器的网络地址发生变动&#xff0c;修改jenkins服务器IP地址后&#xff0c;jenkins网页能够打开&#xff0c;但是job中的配置钩子没有自动改变&#xff0c;如图所示&#xff1a; 经过查询资料了解&#xff0c;需要修改jenkins本地化配置地址才可以显示正确&#xff1a; 1、…