优先级队列(PriorityQueue 和 Top-K问题)

news2024/11/28 12:52:32

一、PriorityQueue

  java中提供了两种优先级队列:PriorityQueue 和 PriorityBlockingQueue。其中 PriorityQueue 是线程不安全的,PriorityBolckingQueue 是线程安全的。

  PriorityQueue 使用的是堆,且默认情况下是小堆——每次获取到的元素都是最小的元素。

  

1. 使用方法

(1)导入包: import java.util.PriorityQueue

(2)要求传入的元素具备比较大小的能力:Comparable | Comparator

(3)不能传入 null,否则会抛出NullPointerException异常

(4)因为默认为小堆,所以优先级最高的元素为最小的元素。若希望优先级最高的元素为最大的元素,则需要使用大堆,即需要用户提供比较器(将比较器对象作为参数传入其构造函数)

2. 内部方法:

(1)构造方法:

PriorityQueue():创建一个空的优先级队列,默认容量为11

PriorityQueue(int  initialCapacity):创建一个初始容量为 initialCapacity 的优先级队列

PriorityQueue(Collection<? extends E>  c):用一个集合来创建优先级队列

如:PriorityQueue<Integer> q = new PriorityQueue<>(list);

(2)常用方法:

① boolean offer(E  e):插入元素 e   O(log(n))

② E peek():获取优先级最高的元素,若优先级队列为空,返回null

③ E poll():删除优先级最高的元素并将其返回,若队列为空,返回null    O(log(n))

④ int  size():获取有效元素的个数

⑤ void clear():清空

⑥ boolean  isEmpty():判断优先级队列是否为空

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

  • 当容量小于 64 时,按照 oldCapacity 的 2 倍扩容
  • 当容量大于 64 时,按照 oldCapacity 的 1.5 倍扩容
  • 当容量超过 MAX_ARRAY_SIZE 时,按照 MAX_ARRAY_SIZE 扩容

二、Top-K问题   

  Top-K问题:在一组数据中,找到最大(最小)的 K 个数。

  不需要对所有数据进行排序,只需要找到符合要求的 K 个数,然后将这 K 个数再进行排序

  如何用堆去解决 Top-K 问题:

假设要在海量数据中找到最大的 K 个数:

(1)要找最大的:建小堆。(因为后序需要用堆顶元素跟其他元素进行比较)

(2)该小堆的最大容量为 K

(3)把剩下的元素挨个和堆顶元素(K个中最小的)进行比较

如果 元素 <= 堆顶元素 : 该元素一定不是最大个K个元素中的元素

如果 元素 > 堆顶元素 :该元素是候选人,用该元素替代堆顶元素 + 向下调整。

  代码的实现可以分两种:直接使用 PriorityQueue 优先级队列、不使用 PriorityQueue 即自己实现其内部的堆。

面试题 17.14. 最小K个数

代码一:直接使用 PriorityQueue 优先级队列以及删除、添加的方法。

class Solution {
    //因为最小的 k 个数,所以需要建大堆
    static class IntegerComparator implements Comparator<Integer> {
        public int compare(Integer o1, Integer o2) {
            //重写比大小的规则
            return o2 - o1;
        }
    }
    public int[] smallestK(int[] arr, int k) {
        //考虑 k == 0
        if (k == 0) {
            return new int[0];
        }
        Comparator<Integer> c = new IntegerComparator();
        PriorityQueue<Integer> p = new PriorityQueue<>(c);

        //将前 k 个数放入堆中
        for (int i = 0; i < k; i++) {
            p.offer(arr[i]);
        }

        //将剩下的元素依次和堆顶元素比较
        //if(元素 >= 堆顶元素):该元素一定不是前 K 个中的元素
        //else(元素 < 堆顶元素):该元素是候选人,用该元素替换堆顶元素 + 向下调整
        //若使用 PriorityQueue ,直接删除堆顶元素,再将元素加入优先级队列中即可。
        for (int i = k; i < arr.length; i++) {
            int e = arr[i];
            int t = p.peek();

            if (e < t) {
                p.poll();
                p.offer(e);
            }
        }

        //整个过程完成后,优先级队列中保存的就是我们需要的 Top-K (最小的k个数)
        //因为题目中,需要返回的是一个数组,所以我们定义一个数组存储 k 个元素。
        int[] ans = new int[k];
        for (int i = 0; i < k; i++) {
            ans[i] = p.poll();
        }
        return ans;
    }

    public void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

代码二:自己实现优先级队列内部的堆操作(数组)

class Solution {
    //因为最小的 k 个数,所以需要建大堆
    public int[] smallestK(int[] arr, int k) {
        //考虑 k == 0
        if (k == 0) {
            return new int[0];
        }
        //创建优先级队列 -> 创建一个大堆
        int[] ans = Arrays.copyOf(arr,k);
        creatHeap(ans, k);
        
        for (int i = k; i < arr.length; i++) {
            if (arr[i] < ans[0]) {
                ans[0] = arr[i];
                
                adjustDown(ans, k, 0);
            }
        }
        return ans;
    }

    //向下调整
    public static void adjustDown(int[] arr, int size, int index){
        //1. "我"是否是叶子结点
        //2. 找到 “我” 的左右孩子中最大的孩子
        //3. 比较“我”和最大孩子的大小:
        //    我 < 最大的孩子 : 交换
        //    我 >= 最大的孩子: 不进行交换
        //4. 交换后更新结点继续向下调整(循环)
        while (index * 2 + 1 < size){
            int maxIdx = index * 2 + 1;
            if (maxIdx + 1 < size && arr[maxIdx] < arr[maxIdx + 1]) {
                maxIdx = maxIdx + 1;
            }

            if (arr[index] >= arr[maxIdx]) {
                break;
            }

            //交换
            int tmp = arr[index];
            arr[index] = arr[maxIdx];
            arr[maxIdx] = tmp;

            index = maxIdx;
        }
    }

    //建大堆
    //从最后一个有孩子的双亲结点开始,向下调整,依次到根结点。
    public static void creatHeap(int[] arr, int size){
        int pIdx = (size - 2)/2;
        
        for (int i = pIdx; i >= 0; i--) {
            adjustDown(arr,size,i);
        }
    }
}

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

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

相关文章

LeetCode刷题------字符串

LeetCode&#xff1a;344.反转字符串 定义两个指针&#xff08;也可以说是索引下标&#xff09;&#xff0c;一个从字符串前面&#xff0c;一个从字符串后面&#xff0c;两个指针同时向中间移动&#xff0c;并交换元素。 var reverseString function(s) {let l -1, r s.len…

Windows下LuaBridge2.8的环境配置及简单应用

Windows下LuaBridge2.8的环境配置及简单应用 LuaBridge2.8下载链接&#xff1a; https://github.com/vinniefalco/LuaBridge/tags 关于Lua的环境配置可参考以下链接&#xff08;这里不做简述&#xff09;&#xff1a; https://ufgnix0802.blog.csdn.net/article/details/125341…

什么是抗压能力?抗压能力的重要性及提高方法

在现实生活中每个人都面临着或大或小的压力。不论是学习还是工作&#xff0c;没有压力就没有进步和提升&#xff0c;压力可以转化为动力&#xff0c;而扛不住压力那就会导致躺平的结果。在职业的道路上&#xff0c;压力一直都存在&#xff0c;尤其是站在企业人力资源管理的角度…

开学季,关于校园防诈骗宣传,如何组织一场微信线上答题考试

开学季&#xff0c;关于校园防诈骗宣传&#xff0c;如何组织一场微信线上答题考试如何组织一场微信线上答题考试在线考试是一种非常节约成本的考试方式&#xff0c;考生通过微信扫码即可参加培训考试&#xff0c;不受时间、空间的限制&#xff0c;近几年越来越受企事业单位以及…

Navicat远程连接mysql教程及Navicat报错10061解决办法

文章目录想要远程连接的前提是数据库要配置密码&#xff0c;配置密码参考如下进入要连接的数据库看一下原有的配置&#xff0c;host 和 user修改配置授权root用户进行远程登录配置修改完成后&#xff0c;打开navicat&#xff0c;新建连接点击测试链接&#xff0c;显示连接后点击…

10个自动化测试框架,测试工程师用起来

软件行业正迈向自主、快速、高效的未来。为了跟上这个高速前进的生态系统的步伐&#xff0c;必须加快应用程序的交付时间&#xff0c;但不能以牺牲质量为代价。快速实现质量是必要的&#xff0c;因此质量保证得到了很多关注。为了满足卓越的质量和更快的上市时间的需求&#xf…

ThinkPad笔记本如何拆卸及安装电池

注意:外置电池可以自行拆卸&#xff0c;内置电池如需拆卸建议联系服务商&#xff0c;由工程师协助操作。 外置电池的拆卸方法&#xff1a; 方式一.部分机型只有一个锁扣&#xff0c;将锁扣移动到解锁状态&#xff0c;然后将电池向机身外侧抽出&#xff08;以T420为例&#xf…

用Qt开发的ffmpeg流媒体播放器,支持截图、录像,支持音视频播放,支持本地文件播放、网络流播放

前言 本工程qt用的版本是5.8-32位&#xff0c;ffmpeg用的版本是较新的5.1版本。它支持TCP或UDP方式拉取实时流&#xff0c;实时流我采用的是监控摄像头的RTSP流。音频播放采用的是QAudioOutput&#xff0c;视频经ffmpeg解码并由YUV转RGB后是在QOpenGLWidget下进行渲染显示。本…

如何使用ModelScope训练自有的远场语音唤醒模型?

就像人和人交流时先会喊对方的名字一样&#xff0c;关键词就好比智能设备的"名字"&#xff0c;而关键词检测模块则相当于交互流程的触发开关。 本文介绍魔搭社区中远场语音增强与唤醒一体化的语音唤醒模型的构成、体验方式&#xff0c;以及如何基于开发者自有数据进…

MySQL数据库07——高级条件查询

前面一章介绍了基础的一个条件的查询&#xff0c;如果多条件&#xff0c;涉及到逻辑运算&#xff0c;and or 之类的。就是高级一点的条件查询。本章来介绍复杂的条件搜索表达式。 AND运算符 AND运算符只有当两边操作数均为True时&#xff0c;最后结果才为True。人们使用AND描述…

高性能IO模型:为什么单线程Redis能那么快?

我们通常说Redis是单线程&#xff0c;主要是指Redis的网络IO和键值对读写是由一个线程来完成的。这也是Redis对外提供键值存储服务的主要流程。 但redis的其他功能&#xff0c;比如持久化、异步删除、集群数据同步等&#xff0c;其实是由额外的线程执行的。 Redis为什么用单线…

探讨MySQL事务特性和实现原理

一、概念 事务 一般指的是逻辑上的一组操作&#xff0c;或者作为单个逻辑单元执行的一系列操作&#xff0c;一个事务中的所有操作会被封装成一个不可分割的执行单元&#xff0c;这个单元的所有操作要么全部执行成功&#xff0c;要么全部执行失败&#xff0c;只要其中任意一个操…

《Terraform 101 从入门到实践》 第四章 States状态管理

《Terraform 101 从入门到实践》这本小册在南瓜慢说官方网站和GitHub两个地方同步更新&#xff0c;书中的示例代码也是放在GitHub上&#xff0c;方便大家参考查看。 军书十二卷&#xff0c;卷卷有爷名。 为什么需要状态管理 Terraform的主要作用是管理云平台上的资源&#xff…

个人学习系列 - 解决拦截器操作请求参数后台无法获取

由于项目需要使用拦截器对请求参数进行操作&#xff0c;可是请求流只能操作一次&#xff0c;导致后面方法不能再获取流了。 新建SpringBoot项目 1. 新建拦截器WebConfig.java /*** date: 2023/2/6 11:21* author: zhouzhaodong* description:*/ Configuration public class W…

Docker-consul的容器服务更新与发现

一.Consul概述1.1 什么是服务注册与发现服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。直到后来出现了多个节点的分布式架构&#xff0c;起…

Threejs中的Shadow Mapping(阴影贴图)

简而言之&#xff0c;步骤如下&#xff1a; 1.从灯光位置视点&#xff08;阴影相机&#xff09;创建深度图。 2.从相机的位置角度进行屏幕渲染&#xff0c;在每个像素点&#xff0c;比较由阴影相机的MVP矩阵计算的深度值和深度图的值的大小&#xff0c;如果深度图值小的话&…

Office Server Document Converter Lib SDK Crack

关于 Office Server 文档转换器 (OSDC) 无需 Microsoft Office 或 Adob​​e 软件即可快速准确地转换文档。antennahouse.com Office Server 文档转换器 (OSDC) 会将您在 Microsoft Office&#xff08;Word、Excel、PowerPoint&#xff09;中创建的重要文档转换为高质量的 PDF …

【编程基础之Python】2、安装Python环境

【编程基础之Python】2、安装Python环境安装Python环境在Windows上安装Python验证Python运行环境在Linux上安装Python验证Python运行环境总结安装Python环境 所谓“工欲善其事&#xff0c;必先利其器”。在学习Python之前需要先搭建Python的运行环境。由于Python是跨平台的&am…

机器学习之K-means原理详解、公式推导、简单实例(python实现,sklearn调包)

目录1. 聚类原理1.1. 无监督与聚类1.2. K均值算法2. 公式推导2.1. 距离2.2. 最小平方误差3. 实例3.1. python实现3.2. sklearn实现4. 运行&#xff08;可直接食用&#xff09;1. 聚类原理 1.1. 无监督与聚类 在这部分我今天主要介绍K均值聚类算法&#xff0c;在这之前我想提一…

01-幂等性解释,问题及常用解决方案

目录 1. 幂等性简介 2. 后端如何解决幂等性问题 2.1 数据库层面 -> 2.1.1 防重表 -> 2.1.2 数据库悲观锁(不建议,容易出现死锁情况) -> 2.1.3 数据库乐观锁 -> 2.1.4 乐观锁CAS算法原理 2.2 锁层面 2.3 幂等性token层面 -> 2.3.1 简介文字描述: …