PriorityQueue详解

2023-10-29

JAVA中PriorityQueue详解

top k算法的经典实现是大顶堆和小顶堆,而在JAVA中可以用PriorityQueue实现小顶堆,话不多说,直接上代码

public static List<Integer> getTopMapNum(int[] arr, int k) {
    Queue<Integer> priorityQueue = new PriorityQueue();
    List<Integer> topKList = new ArrayList<>();
    if (arr == null || k > arr.length || k <= 0) {
        return topKList;
    }
    for (int i : arr) {
        if (priorityQueue.size() < k) {
            priorityQueue.add(i);
        } else {
            if (priorityQueue.peek() < i) {
                priorityQueue.poll();
                priorityQueue.add(i);
            }
        }
    }

    while (k-- > 0) {
        topKList.add(priorityQueue.poll());
    }
    return topKList;
}

作为程序员,只知道简单的如何实现是不够的,最好能够深入源码,下面我们就来聊一聊PriorityQueue

PriorityQueue是优先队列,作用是保证每次取出的元素都是队列中权值最小的,这里涉及到了大小关系,元素大小的评判可以通过元素自身的自然顺序(使用默认的比较器),也可以通过构造时传入的比较器。

Java中PriorityQueue实现了Queue接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。(下图是网上截的,只是这个讲的不是很详细,图还是可以的,所有自己再总结一下,原链接:https://www.cnblogs.com/Elliott-Su-Faith-change-our-life/p/7472265.html

上图中我们给每个元素按照层序遍历的方式进行了编号,如果你足够细心,会发现父节点和子节点的编号是有联系的,更确切的说父子节点的编号之间有如下关系:

leftNo = parentNo*2+1

rightNo = parentNo*2+2

parentNo = (nodeNo-1)/2

通过上述三个公式,可以轻易计算出某个节点的父节点以及子节点的下标。这也就是为什么可以直接用数组来存储堆的原因。

PriorityQueuepeek()element操作是常数时间,add()offer(), 无参数的remove()以及poll()方法的时间复杂度都是log(N)

方法解析(JDK 1.8)

add()和offer

add()方法内部是调用的offer(),所以两个方法没啥区别,都是向队列中插入元素

新加入的元素可能会破坏小顶堆的性质,所以需要进行调整

/**
 * The number of times this priority queue has been
 * <i>structurally modified</i>.  See AbstractList for gory details.
 *队列调整的次数
 */
transient int modCount = 0; // non-private to simplify nested class access
/**
 * The number of elements in the priority queue.
 *队列中元素的个数
 */
private int size = 0;
public boolean add(E e) {
    //add方法内部调用的offer方法
    return offer(e);
}
public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
   //队列调整的次数
    modCount++;
    int i = size;
    //如果队列元素个数大于等于队列的长度,则需要进行扩容
    if (i >= queue.length)
        grow(i + 1);
    size = i + 1;
    //如果是第一个元素,直接插入即可
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);//如果不是第一个元素,则需要进行调整
    return true;
}
/**
 * Increases the capacity of the array.
 *队列扩容
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    //原始队列容量
    int oldCapacity = queue.length;
    // Double size if small; else grow by 50%
    //如果原始队列容量没有超过64,则翻倍扩容,否则扩容50%
    int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                     (oldCapacity + 2) :
                                     (oldCapacity >> 1));
    // overflow-conscious code
    //如果扩容后的队列大小超过了最大队列大小,则需要进行特殊处理
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    queue = Arrays.copyOf(queue, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}
/**
 * Inserts item x at position k, maintaining heap invariant by
 * promoting x up the tree until it is greater than or equal to
 * its parent, or is the root.
 *
 * To simplify and speed up coercions and comparisons. the
 * Comparable and Comparator versions are separated into different
 * methods that are otherwise identical. (Similarly for siftDown.)
 *
 * @param k the position to fill
 * @param x the item to insert
 * 元素添加
 */
private void siftUp(int k, E x) {
    //使用构造方法传进来的比较器
    if (comparator != null)
        siftUpUsingComparator(k, x);
    else
        siftUpComparable(k, x);//使用默认的比较器
}
private void siftUpComparable(int k, E x) {
    Comparable<? super E> key = (Comparable<? super E>) x;
    while (k > 0) {
        //获取父节点的下标
        int parent = (k - 1) >>> 1;
        //父节点的元素值
        Object e = queue[parent];
        //如果新插入的元素比父节点的元素值大,循环结束,新插入节点直接插入最后即可
        if (key.compareTo((E) e) >= 0)
            break;
        //否则需要把父节点元素值放到新插入节点的下标(可以理解为父节点与新插入元素调换位置)
        queue[k] = e;
        //重复进行,知道父节点比子节点小
        k = parent;
    }
    //新插入元素放入排序后的下标
    queue[k] = key;
}

 

 

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PriorityQueue详解 的相关文章

  • Lombok 如何将代码生成到现有类中? [复制]

    这个问题在这里已经有答案了 我可以使用注释处理器从头开始生成类 但我无法像 lombok 那样修改类 我在 android studio 中搜索了 lombok 生成的类 但是我什么也没找到 然后我通过他们的网站检查了龙目岛概述 还在论坛中
  • 如何使用 Windows 上运行的 Java 服务检测用户活动?

    我的目标是使用 Java 创建一个系统监控应用程序 我想知道用户何时在 Windows PC 上进行活动 结果会是这样的 8 00 8 15 活动 9 12 10 29 活动 12 24 15 34 活动 我对任何其他信息 按下了哪个键 使
  • 限制执行第三方软件的线程的权限

    我正在开发一个基于 Eclipse 的应用程序 能够执行第三方组件 不是 eclipse plugin 每个组件都有一个列出权限 以及相应动机 的自定义描述符 这样最终用户可以决定是否执行它 组件在单独的线程中执行 如何根据描述符限制这些线
  • 在Java中,为什么equals()和hashCode()必须一致?

    如果我重写类上的任一方法 它必须确保如果A equals B true then A hashCode B hashCode也一定是真的 有人可以给我看一个简单的例子 如果违反了这一点 就会导致问题吗 我认为这与您是否使用该类作为 Hash
  • 如何将堆栈跟踪转换为字符串?

    转换结果的最简单方法是什么Throwable getStackTrace 到描述堆栈跟踪的字符串 Use Throwable printStackTrace PrintWriter pw https docs oracle com java
  • Apache HttpClient 4.x 在上传较大文件时表现奇怪?

    我正在使用 java 和 scala 开发和测试一个简单的客户端 服务器应用程序 The server是基于com sun net httpserver HttpServer并允许使用 POST 和 PUT 操作通过基本的 RESTful
  • Spring Data JPA 规范继承

    我有三个实体 如下所示 Entity Inheritance strategy InheritanceType JOINED DiscriminatorColumn name type public abstract class Emplo
  • 我应该在远程工作站的哪里放置 CSV 配置文件以进行分布式 JMeter 测试?

    我想做JMeter分布式测试 手册上说首先我应该开始jmeter server在远程节点上 然后我应该更新jmeter config并运行jmeter在主节点上 我做了所有这些步骤 我的测试计划包括使用 CSV 配置文件 如果我只从 1 个
  • 自动装箱是否调用 valueOf()?

    我试图确定以下陈述是否保证为真 Boolean true Boolean TRUE Boolean true Boolean valueOf true Integer 1 Integer valueOf 1 我一直认为自动装箱相当于调用va
  • java应用程序,线程在终止MySQL连接后挂起

    我有一些工作线程正在运行 其中包括 MySQL 和 mysql connector java 5 1 20 当我杀死一些 SQL 语句 使用 mysql 客户端的kill 连接id 时 java线程挂起 这应该抛出一些异常 jstack 打
  • 为什么 (Oracle) JVM 对内存使用有固定上限 (-Xmx)?

    本着提问的精神Java 为什么存在 MaxPermSize https stackoverflow com questions 3356005 java why does maxpermsize exist 我想问一下为什么Oracle J
  • 识别包含本机方法实现的库文件/源

    如何识别包含本机方法实现的库文件 Ex public native String intern 我在哪里可以找到实施 source code of String intern 方法 找到了答案String intern 与快速谷歌搜索 ht
  • Java Reflection:为什么这么慢?

    我一直避免使用 Java 反射 因为它速度缓慢 我在当前项目的设计中达到了一个点 能够使用它将使我的代码更具可读性和优雅性 所以我决定尝试一下 我只是对这种差异感到惊讶 我注意到有时运行时间几乎延长了 100 倍 即使在这个简单的例子中 它
  • 菜单项标题未显示

    菜单项的标题未显示在片段内 我在菜单文件中有两个项目 第一个是带有图标和标签的showAsAction always在工具栏中显示图标 第二个只有标题 我不知道这里出了什么问题 菜单项的所有操作均有效 例如下面 菜单 销售 xml menu
  • JRuby调用了错误的方法

    我在调用 Java 方法时遇到了一个奇怪的问题JRuby http en wikipedia org wiki JRuby 在我的 Java 类中 这些方法定义了两次 看来 JRuby 调用了错误的方法 所以我尝试使用java method
  • 方法中缺少 return 语句错误

    我正在尝试编写一个返回计算机 MAC 地址字符串的静态方法 该函数本身可以在此处找到 http www mkyong com java how to get mac address in java http www mkyong com j
  • 在java中访问dll方法

    我正在尝试访问java中用c 编写的dll方法 从下面的代码我试图构建已成功生成的 dll using System using Microsoft Win32 namespace CyberoamWinHelper public clas
  • Java中ThreadFactory的使用

    有人可以简要解释一下如何以及何时使用 ThreadFactory 吗 使用和不使用 ThreadFactory 的示例可能确实有助于理解差异 Thanks 这是一种可能的用法 假设您有一个ExecutorService它执行你的Runnab
  • DocumentBuilder 解析产生无效字节 2 of 4 字节 UTF-8 序列错误

    我正在尝试解析包含字符串的字节数组Impresi n in XML final DocumentBuilderFactory builderFactory DocumentBuilderFactory newInstance final D
  • Tomcat 中 JNDI 的 Java Mail API 配置文档

    我花了几天时间弄清楚如何通过 JNDI 在 Tomcat 中配置 javax mail Session有认证 现在我明白了 但只是在深入研究代码之后 这次我看到了有史以来最糟糕的代码 javax mail Service connect S

随机推荐

  • 寒假:jQuery

    1
  • activeMq集群实现方式

    前提 都是通过 networkConnectors 这个节点来配置的 安装就不说了 请自行百度一下 配的是虚拟集群 如果有多台机器 其实就不需要修改端口了 可以省去不看 第一种方案 有两台activemq 来集群 一台端口为 8161 服务
  • 解决Eclipse报errors running builder ‘javascript validator’ on project

    问题描述 导入jquery的js到项目中 Eclipse每次检测到功能代码变化 保存动作触发 就报错 errors running builder javascript validator on project 解决方案 1 选择Prope
  • 火遍全世界的网红美女李子柒一年能赚多少钱,数据量化给你看,连中央媒体都为她打call...

    转载自 挖数 未经允许不得二次转载 李子柒可谓是油管 Youtube 第一华人网红 在油管上拥有752万粉丝 截至目前共拍了104段视频 每段视频都有500 2000多万的播放量 这个播放量已经超过了油管全球粉丝最多的T Series 以及
  • ospf,三层交换机,热备,以太网通道练习实验(含命令)

    作者 小刘在这里 每天分享云计算网络运维课堂笔记 疫情之下 你我素未谋面 但你一定要平平安安 一 起努力 共赴美好人生 夕阳下 是最美的 绽放 愿所有的美好 再疫情结束后如约而至 目录 一 简介 二 图纸 三 命令 Switch0 Swit
  • PowerMock 入门

    介绍 PowerMock是一个Java模拟框架 用于解决测试问题 PowerMock 由Mockito和EasyMock两部分API构成 它必须要依赖测试框架 当前PowerMock支持Junit和TestNG 两种测试框架 针对Junit
  • 区块链初步了解

    区块链本质上就是一个共享数据库运用了数学 密码学 计算机和互联网的多项技术 里面的内容不可修改 可以追溯并且可以被每一位用户查询 公开且透明适当下关注的焦点 区块链有四个核心技术分布式账本 非对称加密 共识机制 智能合约 分布式账本是建立多
  • UAP 前台页面间传参数

    场景描述 从A页面点击按钮跳转到B页面 同时把参数传递过去 一 在A页面的MainViewController js中写方法 二 在B页面的index jsp中接收 三 在B页面的MainViewController js中直接调用
  • 100天精通Python(数据分析篇)——第48天:数据分析入门知识

    文章目录 1 为什么要学数据分析 2 数据分析的概念 3 数据分析涉及哪些能力 4 数据分析的流程 5 Python做数据分析学什么 1 为什么要学数据分析 近两年来 数据分析师的岗位需求非常大 90 的岗位技能需要掌握Python作为数据
  • 登录验证码

    登录验证是一般系统都会有的功能 验证的方式也多种多样 比如输入式验证码 拖动式验证条 拖动式验证拼图等等 我们这里先实现常规的输入验证码的方式 右边显示验证码图片 点击可刷新 左边输入验证码 如下图为实现的效果
  • 《再也不怕elasticsearch》es的进阶查询

    ES的进阶查询 大家好我是迷途 一个在互联网行业 摸爬滚打的学子 热爱学习 热爱代码 热爱技术 热爱互联网的一切 再也不怕elasticsearch系列 帅途会慢慢由浅入深 为大家剖析一遍 各位大佬请放心 虽然这个系列帅途有时候更新的有点慢
  • 08模板学习之自己写一个模板数组MyArray案例(等号重载为什么要返回引用)

    08模板学习之自己写一个模板数组MyArray案例 等号重载为什么要返回引用 1 案例代码 注意 因为是模板类的编写 所以直接写在同一文件 不必注意 h和 cpp分离时重载运算符的声明或者友元函数的声明 文件命名为 MyArray hpp
  • 虚拟ip是真实访问你的服务器吗,浅谈windows操作系统下虚拟ip

    生活场景中 经常会看到 局域网内 多个不同客户端设备 将数据发送到服务器上 而服务器要求一个客户端一个IP 如图1 1所示 多个客户端A B C通过路由器M连接到服务器N 图1 1 作为一名 搬砖 码农 要把服务器最大连接客户端设备的数量
  • CentOS服务器配置PHP环境(PHP+Apache+MySQL)

    腾讯云服务器用的是 CentOS 7 4 64位镜像 一 登录服务器 二 安装Apache 1 安装 yum y install httpd 2 开启apache服务 systemctl start httpd service 3 设置ap
  • 四十九.队列C语言实现

    include
  • Python Pandas之DataFrame

    和一个ndarray一样 我们通过shape ndim dtype了解这个ndarray的基本信息 那么对于DataFrame我们有什么方法了解呢 DataFrame的基础属性 df shape 行数列数 df dtypes 列数据类型 d
  • Auto CAD:CAD三维建模设计之渲染工具(光源、阳光和位置、材质、渲染)之详细攻略

    Auto CAD CAD三维建模设计之渲染工具 光源 阳光和位置 材质 渲染 之详细攻略 目录 CAD三维建模设计之渲染工具 光源 阳光和位置 材质 渲染 光源 阳光和位置
  • 最新爆料!RK3588 适配 OpenHarmony 的新进展

    前言 根据最新爆料 在鸿湖万联团队的努力下 当前已完成了RK3588基于全新的硬件架构 ARM Mali G610 在OpenHarmony操作系统上第一阶段的适配工作 下一步计划正在稳步推进中 进展喜人 下面先为大家爆料当前的最新进展 R
  • js读取Excel 文件并依据指定内容生成sql文件

    最近接到个需求是通过excel文件生成数据库 于是便做了这么个工具 开发思路 1 读取Excel文件 2 将内容转换为sql 3 生成对应类型的sql文件 读取Excel 使用现成的工具 xlsx core js xlsx core js
  • PriorityQueue详解

    JAVA中PriorityQueue详解 top k算法的经典实现是大顶堆和小顶堆 而在JAVA中可以用PriorityQueue实现小顶堆 话不多说 直接上代码 public static List