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

server/2025/2/5 20:15:13/

目录

PriorityQueue%C2%A0%20%C2%A0%20%C2%A0%C2%A0-toc" name="tableOfContents" style="margin-left:0px">一、PriorityQueue 

PriorityQueue%E7%9A%84%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95-toc" name="tableOfContents" style="margin-left:0px">二、PriorityQueue的构造方法

1、不带参数

2、带参数 

3、用一个集合来创建 

4、创建比较器

PriorityQueue%E7%9A%84%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95-toc" name="tableOfContents" style="margin-left:0px">三、PriorityQueue的操作方法

1、boolean offer(E e)插入

2、E peek()获取

3、E pool()删除

4、int size()长度

5、void clear()清空

6、Boolean isEmpty()判空 

四、的应用

PriorityQueue%E7%9A%84%E5%AE%9E%E7%8E%B0%C2%A0-toc" name="tableOfContents" style="margin-left:40px">1、PriorityQueue的实现 

2、排序

五、Top-k问题

(1)直接排序

PriorityQueue%E8%BF%9B%E8%A1%8C%E5%8D%87%E5%BA%8F%E6%8E%92%E5%BA%8F-toc" name="tableOfContents" style="margin-left:40px">(2)利用PriorityQueue进行升序排序

(3)Top-k算法


PriorityQueue%C2%A0%20%C2%A0%20%C2%A0%C2%A0" name="PriorityQueue%C2%A0%20%C2%A0%20%C2%A0%C2%A0">一、PriorityQueue 

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

注意事项:

  • PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException异常
  • 不能插入null对象,否则会抛出NullPointerException
  • 没有容量限制,可以插入任意多个元素,其内部可以自动扩容
  • 插入和删除元素的时间复杂度为O(logn)
  • PriorityQueue底层使用了数据结构
  • PriorityQueue默认情况下是---即每次获取到的元素都是最小的元素

PriorityQueue%E7%9A%84%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95" name="%E4%BA%8C%E3%80%81PriorityQueue%E7%9A%84%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95">二、PriorityQueue的构造方法

1、不带参数 PriorityQueue<>()

java">创建⼀个空的优先级队列,底层默认容量是11 
PriorityQueue<Integer> q1 = new PriorityQueue<>();

2、带参数 PriorityQueue<>(int initialCapacity)

java">创建⼀个空的优先级队列,底层的容量为initialCapacity 
PriorityQueue<Integer> q2 = new PriorityQueue<>(100);
此时底层容量为100

注意:此时initialCapacity的值不能小于1,否则就会抛出illegalArgumentException异常

3、用一个集合来创建 PriorityQueue(Collection<? extends E> c)

java">⽤ArrayList对象来构造⼀个优先级队列的对象ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);
q3中已经包含了三个元素 
PriorityQueue<Integer> q3 = new PriorityQueue<>(list);

4、创建比较器

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

我们可以自己定义的比较器:直接实现 Comparator 接口,然后重写该接口中的 compare 方法即可

java">class ImBig implements Comparator<Integer> {public int compare(Integer o1,Integer o2){return o2.compareTo(o1);
//Byte,Double,Integer,Float,Long或Short类型的参数可以利用compareTo方法进行比较,
//大于返回1,等于返回0,小于返回-1//return o2-o1;
//当然我们也可以返回两个数的差值o2-o1,当然如果我们传入的两个参数是ListNodee类型的,
//我们就不能使用compareTo方法,而是使用差值来比较}
}public static void main(String[] args) {PriorityQueue<Integer> queue = new PriorityQueue<>(new ImBig());queue.offer(1);queue.offer(-1);queue.offer(6);System.out.println(queue.poll());}

此时我们来删除我们的第一个元素由于实现的是大根,此时要删除的元素应该为我们的大根的根结点即最大的元素6。

 默认情况下,PriorityQueue队列是,那么我们不实现比较器,我们删除的应该是我们的最小的元素-1.

但是有的情况下我们可能还是需要创立小的比较器

java">class ImLess implements Comparator<Integer>{public  int compare(Integer o1,Integer o2){return o1.compareTo(o2);//return o1-o2;}
}

PriorityQueue%E7%9A%84%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95" name="%E4%B8%89%E3%80%81PriorityQueue%E7%9A%84%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95">三、PriorityQueue的操作方法

1、boolean offer(E e)插入

插入元素e,插入成功返回true,如果e对象为空,抛出NullPointerException异常,时间复杂度 O(logn)

注意:空间不够时候会自主扩容

 在上面其实我们已经使用了,大小根的插入

注意:在插入的过程中可能会超出他的默认容量,但是PriorityQueue会自动扩容,他的扩容机制是:

  • 如果容量小于64时,是按照oldCapacity(原来空间)的2倍方式扩容的
  • 如果容量大于等于64,是按照oldCapacity(原来空间)的1.5倍方式扩容的
  • 如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容

2、E peek()获取

获取优先级最高(顶)的元素,如果为空,返回null 

获取大根顶元素:

获取小根顶元素: 

3、E pool()删除

移除优先级最高的元素并返回,如果为空,返回null。 

如果我们此时删除大根顶元素,我们进行打印就会的到要删除的顶元素,此时我们在查询顶元素就不是原来的值了,而peek并不会删除。

4、int size()长度

他得到的长度是获取的有效元素个数 

5、void clear()清空

此时他会清空队列中的所有元素,此时队列的有效长度应为0

6、Boolean isEmpty()判空 

 检测是否为空,空返回true,不为空返回false

四、的应用

PriorityQueue%E7%9A%84%E5%AE%9E%E7%8E%B0%C2%A0" name="1%E3%80%81PriorityQueue%E7%9A%84%E5%AE%9E%E7%8E%B0%C2%A0">1、PriorityQueue的实现 

PriorityQueue的实现是用作为底层结构封装优先级队列,因此PriorityQueue的大小根是根据排序来实现的。

2、排序

排序即利用的思想来进行排序,总共分为两个步骤:

(1)建

  • 升序:建大
  • 降序:建小

(2)利用删除思想来进行排序

我们以升序来举例,首先我们先建立一个大根,我们将大根第一个元素(即最大的的元素)最后一个元素进行交换,然后我们将交换后的第一个元素进行向下调整,要注意的是我们此时调整的范围是交换完后第一个元素到交换完后最后一个元素之前,调整完后,再让第一个元素个新的最后一个元素进行交换,直到最后一个元素的位置和第一个元素位置重合。接下来我们来看以下我们的过程图:

同理,降序就是创建一个小根进行调整

完整代码

java">//创建一个大根 
public void createHeap(){for(int parent = (usesize-1-1)/2;parent >=0 ;parent--){sifDown(parent,usesize);}}
//向下调整public void sifDown(int parent,int usesize){int child = 2*parent + 1;while(child < usesize){//孩子的位置是小于我们所给的长度的if(child+1 < usesize && elem[child] < elem[child+1]){child++;}if(elem[child] > elem[parent]){swap(child,parent);parent = child;child = 2*parent + 1;}else{break;}}}
//排序public void Heapsort(){int end = usesize-1;//end的下标为有效长度减一while(end > 0){//不重合就进行调整swap(0,end);//交换sifDown(0,end);//调整end--;//改变end的位置
//注意这里先交换后改变end,是因为在调整过程整孩子的位置是小于我们所给的长度的}}

五、Top-k问题

Top-k问题:最小k个数

这个问题就是让我们求前k个最小的元素,对于这道题其实我们有三种解题方法

(1)直接排序

第一种,也是最简单的方法,直接将数组进行排序,找到前k个元素并打印打印

PriorityQueue%E8%BF%9B%E8%A1%8C%E5%8D%87%E5%BA%8F%E6%8E%92%E5%BA%8F" name="%EF%BC%882%EF%BC%89%E5%88%A9%E7%94%A8PriorityQueue%E8%BF%9B%E8%A1%8C%E5%8D%87%E5%BA%8F%E6%8E%92%E5%BA%8F">(2)利用PriorityQueue进行升序排序

原理:就是上面所讲的将他建立成一个大根然后利用排序进行升序排序,实际上就是直接向PriorityQueue中传值,然后打印前k个

java">public int[] smallestK(int[] arr, int k) {PriorityQueue<Integer> queue = new PriorityQueue<>();for(int i = 0;i < arr.length;i++){queue.offer(arr[i]);}int[] ret = new int[k];for(int j = 0;j < k;j++){ret[j] = queue.poll();}return ret;}

(3)Top-k算法

我们建立前k个大根,之后将N-k个元素与顶元素进行比较,如果顶元素小,就弹出元素,然后将这个小的元素入,然后对进行调整,之后再重复上述过程,直到将所有元素比完,最后弹出前K个元素。 

过程图:

java">class ImBig1 implements Comparator<Integer>{public int compare(Integer o1,Integer o2){return o2.compareTo(o1);}}class Solution {public int[] smallestK(int[] arr, int k) {int[] ret = new int[k];if(arr.length <k || k <= 0){return ret;}PriorityQueue<Integer> queue = new PriorityQueue<>(new ImBig1());for(int i = 0;i<k;i++){queue.offer(arr[i]);}for(int j = k;j < arr.length;j++){int tmp = queue.peek();if(tmp > arr[j]){queue.poll();queue.offer(arr[j]);}}for(int i = 0;i < k;i++ ){ret[i] = queue.poll();}return ret;}}

好了,今天的分享就到这里了,还请大家多多关注,我们下一篇见!


http://www.ppmy.cn/server/165223.html

相关文章

【25考研】考研366是否能进北航计算机复试?该怎么准备?

366分对于北航来说可能有擦边进复试的风险&#xff0c;建议同学还是尽早准备复试&#xff0c;争取逆风翻盘&#xff0c;顺利上岸&#xff01; 北航计算机复试有机试&#xff0c;而且是先机试&#xff0c;第二天再进行复试。 一、复试内容 根据以往的经验&#xff0c;材料提交的…

流式学习(简易版)

最近读论文看到了这个概念&#xff0c;感觉还挺有意思的 流形(Manifold) 广泛应用于多个领域&#xff0c;如几何学、物理学、机器学习等。流形本质上是一个局部类似于欧几里得空间的空间&#xff0c;即它在某些尺度下看起来像我们熟悉的平面或曲面&#xff0c;但整体结构可能是…

Nacos 的介绍和使用

1. Nacos 的介绍和安装 与 Eureka 一样&#xff0c;Nacos 也提供服务注册和服务发现的功能&#xff0c;Nacos 还支持更多元数据的管理&#xff0c; 同时具备配置管理功能&#xff0c;功能更丰富。 1.1. windows 下的安装和启动方式 下载地址&#xff1a;Release 2.2.3 (May …

pytorch实现长短期记忆网络 (LSTM)

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 LSTM 通过 记忆单元&#xff08;cell&#xff09; 和 三个门控机制&#xff08;遗忘门、输入门、输出门&#xff09;来控制信息流&#xff1a; 记忆单元&#xff08;Cell State&#xff09; 负责存储长期信息&…

Vue.js 使用组件库构建 UI

Vue.js 使用组件库构建 UI 在 Vue.js 项目中&#xff0c;构建漂亮又高效的用户界面&#xff08;UI&#xff09;是很重要的一环。组件库就是你开发 UI 的好帮手&#xff0c;它可以大大提高开发效率&#xff0c;减少重复工作&#xff0c;还能让你的项目更具一致性和专业感。今天…

面试--你的数据库中密码是如何存储的?

文章目录 三种分类使用 MD5 加密存储加盐存储Base64 编码:常见的对称加密算法常见的非对称加密算法https 传输加密 在开发中需要存储用户的密码&#xff0c;这个密码一定是加密存储的&#xff0c;如果是明文存储那么如果数据库被攻击了&#xff0c;密码就泄露了。 我们要对数据…

19C RAC在vmware虚拟机环境下的安装

RAC安装规划 ===IP== ORA19C01 public ip : 192.168.229.191 heatbeat : 192.168.0.1 vip : 192.168.229.193 ORA19C02 public ip :192.168.229.192 heatbeat : 192.168.0.2 vip : 192.168.229.194 scan ip 192.168.229.195 hosts: echo "192.168.229…

自学习记录-编程语言的特点(持续记录)

我学习的顺序是C -> python -> C -> Java。在讲到某项语言的特点是&#xff0c;可能会时不时穿插其他语言的特点。 Java 1 注解Annotation Python中也有类似的Decorators。以下为AI学习了解到的&#xff1a; Java的Annotation是一种元数据&#xff08;metadata)&a…