Java-数据结构-优先级队列(堆)-(二) (゚▽゚*)

news2024/9/20 15:39:12

文本目录:

❄️一、PriorityQueue的常用接口:

          ➷ 1、PriorityQueue的特性:

          ➷ 2、使用PriorityQueue的注意:

           ➷ 3、PriorityQueue的构造:

    ☞  1、无参数的构造方法:

     ☞  2、有参数的构造方法:

     ☞  3、带一个参数comparator的构造方法:

     ☞  4、用集合的构造方法:

           ➷ 4、PriorityQueue的插入和删除等方法:

    ☞  1、插入方法(offer(E e)):

    ☞  2、删除方法( poll() ) 和 查看优先级最高的( peek() ):

     ☞  3、获得有效元素的个数( size() ):

     ☞  4、判空( isEmpty() ):

 ❄️二、堆的应用:

          ➷ 1、PriorityQueue的实现:

          ➷ 2、堆排序:

          ➷ 3、Top-k问题:

  ❄️总结:


❄️一、PriorityQueue的常用接口:

          ➷ 1、PriorityQueue的特性:

        在 Java 集合中给我们提供了两种优先级队列:PriorityQueuePriorityBlockingQueue,它们肯定是有区别的,我们的 PriorityQueue  线程不安全PriorityBlockingQueue 线程安全的 ,我们这次呢主要介绍 PriorityQueue 

         我们还是请出我们的老朋友:

我们可以看到我们的  PriorityQueue  是实现 Queue 这个接口的。


          2、使用PriorityQueue的注意:

在我们使用  PriorityQueue  的时候我们要注意:


1、在我们使用  PriorityQueue  的时候我们需要导入包:

所以我们一定要导包。


 2、 PriorityQueue  中存放的数据必须是可以比较大小的,不能插入无法比较大小的对象,否则          会抛出 ClassCastException 异常。

     因为我们的优先级队列需要比较对象之后才进行存入,这时候我们比较时候要强转成 Comparable 这个,我们来看看这个的底层代码:

所以我们必须要存入可以比较的对象。 


3、我们不能插入 null 对象,否则会抛出 NullPointerException 这个异常。我们来看:

存入 null 就会抛出异常。 


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


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


6、 PriorityQueue 底层使用了堆的数据结构。


7、 PriorityQueue 默认情况下是 小堆 ------ 就是每次获得堆里最小的元素


           3、PriorityQueue的构造:

     我们的 优先级队列 的构造方法常见的有几种构造方法,我们来一一介绍来看,但是呢在我们介绍构造方法之前呢,我们来看看 优先级队列 的底层代码的一些代码:


    ☞  1无参数的构造方法:

我们来看看这个无参构造的底层代码:

public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

 这里呢我们调用的两个参数的构造方法,我们的 容量是默认的 11 个容量。


     ☞  2有参数的构造方法:

   我们同样先来看看底层的代码:

public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }

这个呢就是创建一个 容量 为 initialCapacity 这个容量的 优先级队列

这里调用的同样是两个参数的构造方法。

这里要注意我们传入的参数不能 < 1。


     ☞  3带一个参数comparator的构造方法:

public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }

这里同样是调用带两个参数的构造方法,我们传入的是一个比较器。容量 还是 11 这个默认参数


接下来我们来看看对于这几个构造方法所调用的 两个参数的构造方法是什么样的:

public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

这个就是我们的底层代码。 

这里我们会直接把传入的参数直接给到 queue 这个的容量。之后把第二个参数给到我们的比较器 


     ☞  4用集合的构造方法:

我们还是先来看看底层代码:

public PriorityQueue(Collection<? extends E> c) {
        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            initElementsFromCollection(ss);
        }
        else if (c instanceof PriorityQueue<?>) {
            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            initFromPriorityQueue(pq);
        }
        else {
            this.comparator = null;
            initFromCollection(c);
        }
    }

这里就是我们传入的集合会直接给到我们的数组中,来构造。 


           4、PriorityQueue的插入和删除等方法:

    这里呢我们只介绍一下关于插入方法的操作的流程,其余的呢,我们看一下演示结构,因为和我们上次博客实现的堆的方法原理是一样的。


    ☞  1、插入方法(offer(E e)):

     我们在上一个博客中已经介绍了堆的插入是如何实现的了,这里呢是类似的,我们在这里呢,我们直接来看看这个方法在Java中的执行流程图:  

    这里的 compareTo 这个方法默认的是 this.val - o.val 在上面就是 15 - 11,这样得到的就是小根堆如果我们想要实现大根堆,就把其变成 o.val - this.val 就可以了,我们来看看如何实现的: 


    ☞  2、删除方法( poll() ) 和 查看优先级最高的( peek() ):

我们来看看删除优先级最高的栈顶数据:


     ☞  3、获得有效元素的个数( size() )


     ☞  4、判空( isEmpty() )


 ❄️二、堆的应用:

          ➷ 1、PriorityQueue的实现:

     我们的 PriorityQueue 的底层使用的就是堆来实现的。


          ➷ 2、堆排序:

     堆排序就是使用堆的思想来实现排序,我们的排序有两种排序,升序 和 降序,我们分为来那个步骤来进行堆排序:

    1、建堆:

升序:建大堆。

降序:建小堆。

    2、利用堆删除的思想来进行排序:

      我们来使用堆排序 创建升序 来进行介绍如何建成堆排序。

      就是把一个 大根堆 的 第一个数据和最后一个数据进行交换,之后我们把交换完的第一个数据向下调整,再次变成大根堆但是要注意,我们交换完之后的位置不用再调整,我们这时候要使用 一个 临时变量进行记录 我们 向下调整 的判断是否结束的位置。我们来看看流程图:

这个理解之后呢,我们来看看这个对于 使用大根堆来实现升序 的代码要如何实现: 

 private void shiftDown(int parent,int usedSize) {
        int child = parent * 2 + 1;//parent根节点的左子树的节点

        while (child < usedSize) {

            //判断有没有右子树,如果有就把 child 设置为最大的值的下标
            if (child + 1 < usedSize && elem[child + 1] > elem[child]) {
                //右子树比左子树大把 child + 1,就是右子树
                child += 1;
            }

            if (elem[parent] < elem[child]) {
                //进行交换
                swap(elem,child,parent);
                //调整完,把 parent 和 child 进行调整位置
                parent = child;
                child = parent * 2 + 1;
            }else {
                //这是 parent下标的值大于child,跳出
                break;
            }
        }
    }

    private void swap(int[] elem,int i,int j) {
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }
//这是我们的上次博客的代码。我们自实现的建立大根堆

public void HeapSort() {
        //我们把第一个数据和最后一个数据进行交换
        //之后我们把 0 下标的值进行向下排序,这样之后我们会把大值放后面,小值放堆的前面
        int end = usedSize - 1;
        while (end > 0){
          swap(elem,0,end);
          shiftDown(0,end);
          end--;
        }
    }

     这就是我们的使用 大根堆进行排升序。对于 降序我们要使用建小堆来实现,我们和 用大堆实现升序就是思想是差不多的。


          ➷ 3、Top-k问题:

这个也是我们出现过的面试题。

                      ▶  Top-k的传送门:

                                       Top-k问题的最小k个数

     这个问题呢,就是求数据集合中前 k 个最大的元素或者是最小的元素,一般情况下呢都是数据比较多的情况下。

     我们对于这个问题呢,我们有三种不同的做法,假设我们有N个数据,我们来看:

1、直接排序,直接找到前 k 个。

2、建立一个我们有 N 个数据的堆,之后出前k个数据。

      就是如果求前 k 个最小的数据就是建小根堆。求前 k 个最大的数据就是建大根堆。

3、 比如我们求前k个最小的元素,我们执行:建立前k个大根堆,之后我们把N-K个元素和堆顶元         素进行比较,如果比堆顶的元素小,就把堆顶的数据删除,之后再把这个小的元素入堆

       对于求前k个最大的元素就是反之。(这个方法就是我们Top-k问题的最好的解决办法)

我们来看流程图:

    这样呢就是我们的最好的解决 Top-k 问题的思路了,之后理解这个之后呢,我们来看看我们的Top-k的代码如何编写:

class IntComp implements Comparator<Integer> {
    //这是把其变成大根堆
    @Override
    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 == null || k == 0) {
            return ret;
        }
        //默认为小堆,我们传比较器
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k,new IntComp());

        //把前k个元素放入到堆中
        for (int i = 0; i < k; i++) {
            priorityQueue.offer(arr[i]);
        }

        //之后从第 N-k 个数据开始比较知道比较结束
        //这里是求前k个最小的,所以把第 N-k 个数据和 堆顶进行比较,如果 N-k 小的话就是 删堆顶,入第N-k的元素堆
        for (int i = k; i < arr.length; i++) {
            int peekval = priorityQueue.peek();
            if (arr[i] < peekval) {
                priorityQueue.poll();
                priorityQueue.offer(arr[i]);
            }
        }

        //把堆里的元素放到数组中
        for (int i = 0; i < k; i++) {
            ret[i] = priorityQueue.poll();
        }

        return ret;
    }
}

    ※   注意:这里我们的 PriorityQueue 创建为什么要传参呢?因为我们默认的建堆方式是小根堆,我们是求前k个最小的元素,所以我们要建大根堆,所以我们要传比较器,使之变成大根堆。


  ❄️总结:

      OK,我们这次的博客就到这里就结束了,这里呢还是比较难理解的,所以我们要多进行练习一下,那么我们下次的博客呢,就开始接受我们的排序的问题了,这个排序还是很重要的,我们尽情期待吧!!!拜拜咯~~~

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

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

相关文章

DCMM介绍

目录 一、介绍 二、核心摘要 三、体系大纲 四、能力评估 1、过程与活动 2、等级判定依据 3、访谈对象 一、介绍 通过阅读本书,您将洞悉国际数据框架体系,并掌握国家对于数据管理能力的权威评估标准与等级划分。本书详尽阐述了数据管理领域的八大核心能力域,以及这八大…

Flask、Werkzeug 和 WSGI 间的关系

一.Flask、Werkzeug和 WSGI 关系 1.WSGI Web 架构 Flask 是一个基于 Werkzeug 和 Jinja2 模板引擎的轻量级 Web 框架。Werkzeug 是 Flask 的底层 WSGI 工具包&#xff0c;它提供了 WSGI 服务器、请求和响应对象、路由等基础功能&#xff0c;Flask 在此基础上构建了更高级的 W…

HelpLook VS GitBook,在线文档管理工具对比

在线文档管理工具在当今时代非常重要。随着数字化时代的到来&#xff0c;人们越来越依赖于电子文档来存储、共享和管理信息。无论是与团队合作还是与客户分享&#xff0c;人们都可以轻松地共享文档链接或通过设置权限来控制访问。在线文档管理工具的出现大大提高了工作效率和协…

性能调优

性能调优 应用程序在运行过程中经常会出现性能问题&#xff0c;比较常见的性能问题现象是&#xff1a; 通过top命令查看CPU占用率高&#xff0c;接近100甚至多核CPU下超过100都是有可能的。请求单个服务处理时间特别长&#xff0c;多服务使用skywalking等监控系统来判断是哪一…

电子束光刻过程中的场拼接精度

以下内容如有错误&#xff0c;请不吝指教&#xff0c;感谢&#xff01; 1、EBL为什么会出现场拼接误差&#xff0c;如何解决&#xff1f; ChatGPT 说&#xff1a; 在电子束光刻&#xff08;EBL&#xff09;过程中&#xff0c;SOI&#xff08;硅绝缘体&#xff09;芯片上出现*…

计算机毕业论文题目:设计与实现一个校园通知信息系统

设计与实现一个校园通知信息系统是一个涉及多个方面的复杂项目&#xff0c;它旨在提高信息传递的效率和准确性&#xff0c;确保学生、教师以及学校管理人员能够及时获取到重要的通知信息。以下是关于如何设计并实现这样一个系统的详细说明&#xff1a; 1. 需求分析 用户…

【高中数学/不等式/数学归纳法/等比数列】证明伯努利不等式(1+h)^n>1+nh的三种方式

【伯努利不等式】 (1h)^n>1nh &#xff08;h>0,n为大于1的自然数&#xff09; 【数学归纳法证法】 证明&#xff1a; n2时&#xff0c;(1h)^212hh^2>12h 不等式成立 n3时&#xff0c;(1h)^313h3h^2h^3>13h 不等式成立 假设nk时&#xff0c;有(1h)^k>…

机房三大网络拓扑图,太实用了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 通常来说&#xff0c;机房的三大网络拓扑图指的是星型拓扑、总线型拓扑和环形拓扑。 在实际的机房网络设计中…

vue项目加载cdn失败解决方法

注释index.html文件中 找到vue.config.js文件注释、

MySQL_图形管理工具简介、下载及安装(超详细)

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

【VUE3.0】动手做一套像素风的前端UI组件库---先导篇

系列文章目录 【VUE3.0】动手做一套像素风的前端UI组件库—Button 目录 系列文章目录引言准备素材字体鼠标手势图 创建vue3项目构建项目1. 根据命令行提示选择如下&#xff1a;2. 进入项目根目录下载依赖并启动。3. 设置项目src路径别名&#xff0c;方便后期应用路径。4. 将素…

Debian 12上安装google chrome

当前系统&#xff1a;Debian 12.7 昨天在Debian 12.7上安装Google Chrome时&#xff0c;可能由于网络原因&#xff0c;导入公钥始终失败。 导致无法正常使用命令#apt install google-chrome-stable来安装google chrome; 解决办法&#xff1a; Step1.下载当前google chrome稳…

C++性能优化-代码角度

减少跳转/分支语句和函数调用 原因 分支语句&#xff1a;当 CPU 执行到分支语句时&#xff0c;将会进行分支预测&#xff08;对大部分PC&#xff09;。如果分支预测错误&#xff0c;就会清空已经预取和执行的部分指令&#xff0c;重新从正确的分支开始取指和执行&#xff0c;…

某东-h5st参数逆向分析

目标&#xff1a;商品搜索翻页接口 直接搜索h5st就可以搜到&#xff0c;所有可疑位置都打上断点&#xff0c;然后翻页&#xff0c;最终断点位置&#xff1a; window.PSign.sign(colorParamSign)是异步代码&#xff0c;colorParamSign是传入的参数&#xff0c;执行后把包含h5st…

基于YOLOv5的教室人数检测统计系统

基于YOLOv5的教室人数检测统计系统可以有效地用于监控教室内的学生数量&#xff0c;适用于多种应用场景&#xff0c;比如 自动考勤、安全监控或空间利用分析 以下是如何构建这样一个系统的概述&#xff0c;包括环境准备、数据集创建、模型训练以及如何处理不同类型的媒体输入…

【机器学习】--- 序列建模与变分自编码器(VAE)

在机器学习领域&#xff0c;序列建模与变分自编码器&#xff08;Variational Autoencoder, VAE&#xff09; 是两个至关重要的技术&#xff0c;它们在处理时间依赖性数据与复杂数据生成任务中都发挥着关键作用。序列建模通常用于自然语言处理、语音识别等需要保持顺序关系的任务…

【老板必看!】电脑怎么看使用软件时间记录?一文读懂5种超实用的方法!

在企业管理中&#xff0c;电脑虽不善言语、不会说话&#xff0c;但会留下无数线索&#xff0c;就像一场未解之谜&#xff0c;等待着各位福尔摩斯得到来&#xff0c;去揭开它的秘密面纱。 你是否曾好奇过&#xff0c;当你不在的时候&#xff0c;员工都在用电脑都在忙些什么&…

基于python+django+vue的影视推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于pythondjangovueMySQL的影…

大表数据如何在OceanBase中进行表分区管理的实践

背景 将Zabbix的数据库迁移至OceanBase后&#xff0c;以其中的几个大表作为案例&#xff0c;本文将分享如何利用ODC&#xff08;OceanBase 开发者工具&#xff09;&#xff0c;来进行自动管理OB数据库中的表分区的方案。 因为原始表里已经有大量的数据&#xff0c;如果贸然对…

快速掌握Postman接口测试

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、前言 在前后端分离开发时&#xff0c;后端工作人员完成系统接口开发后&#xff0c;需要与前端人员对接&#xff0c;测试调试接口&#xff0c;验证接口的正…