当前位置: 首页 > news >正文

【数据结构】优先级队列----堆

优先级队列----堆

  • 优先级队列
  • 堆的创建
    • 堆的插入:
    • 堆的删除:
  • PriorityQueue的特性
  • PriorityQueue的构造与方法

优先级队列

优先级队列: 不同于先进先出的普通队列,在一些情况下,优先级高的元素要先出队列。而这种队列需要提供两个基本的操作:返回最高优先级对象添加新的对象。
(JDK1.8中,优先级队列底层使用的是 堆 数据结构,而堆则是在完全二叉树的基础上进行了调整)

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

大小根堆示例
堆的两个性质:
堆中某个结点的值总是不大于或不小于其父节点的值。
堆总是一棵完全二叉树。


堆的存储方式:
堆是一棵完全二叉树,因此可以用层序的规则采用顺序的方式来高效存储,但对于非完全二叉树,就不适合使用顺序方式进行存储,因为为了能够还原二叉树,空间中必须要存储空节
点,就会导致空间利用率比较低。

如果 i 表示孩子结点,则父节点为 (i - 1)/2。
如果 i 表示根结点,左孩子则为 2i + 1,右孩子为 2i + 2。

堆的创建

堆的调整
向下调整过程(以小根堆为例):

  1. 让 parent 标记需要调整的节点,child 标记 parent 的左孩子(完全二叉树中,一定先有左孩子)
  2. 如果 parent 的左孩子存在(child < size),进行以下操作,直到 parent 的左孩子不存在:
    找到左右孩子中较小的结点,和 parent 进行比较,若 parent 小,则调整结束。若 parent 大,则进行交换。交换后,可能会使原来满足堆的子树发生改变,所以需要继续向下调整。

例如:
向下调整过程
代码:

public class TestHeap {public int[] elem;public int usedSize;public TestHeap() {this.elem = new int[10];}//初始化public void initElem(int[] array) {for (int i = 0; i < array.length; i++) {elem[i] = array[i];usedSize++;}}public void createHeap() {//循环调用for (int parent = (usedSize - 1 - 1) / 2; parent >= 0; parent--) {shiftDown(parent, usedSize);}}//向下调整 len为当前有效数据个数private void shiftDown(int parent, int len) {int child = 2 * parent + 1;//最起码 要有左孩子while (child < len) {//一定是有右孩子的情况下if (child + 1 < len && elem[child] > elem[child + 1]) {//保证 child指向较小值child++;}if (elem[child] < elem[parent]) {//孩子结点小于父节点 交换int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;//继续调整下面子树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;//向上调整shiftUp(usedSize-1);}public boolean isFull() {return usedSize == elem.length;}private void shiftUp(int child) {int parent = (child - 1) / 2;while (child > 0) {if (elem[child] < elem[parent]) {int tmp = elem[child];elem[child] = elem[parent];elem[parent] = tmp;//继续往上走child = parent;parent = (child - 1) / 2;}else {break;}}}

堆的删除:

堆的删除
代码:

    public void pop() {if (isEmpty()) {return;}//交换int tmp = elem[0];elem[0] = elem[usedSize - 1];elem[usedSize - 1] = tmp;//有效数据个数减一usedSize--;//向下调整shiftDown(0, usedSize);}public boolean isEmpty() {return usedSize == 0;}

PriorityQueue的特性

Java 集合框架中提供了 PriorityQueue 和 PriorityBlockingQueue 两种类型的优先级队列,PriorityQueue 是线程不安全的,PriorityBlockingQueue 是线程安全的,这里主要介绍PriorityQueue。

使用 PriorityQueue 需要注意:

  1. 使用时必须导入 PriorityQueue 所在的包(import java.util.PriorityQueue;)。

  2. PriorityQueue 中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出 ClassCastException 异常。
    只插入一个元素时,并不会报错:
    添加一个元素
    插入多个元素就会报错:
    多个元素就会报错

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

  4. 内部可以自动扩容。
    自动扩容

  5. 插入和删除元素的时间复杂度为 O(log₂N)。

  6. PriorityQueue 底层使用的是堆数据结构。

  7. PriorityQueue 默认情况下是小堆。
    小堆

PriorityQueue的构造与方法

PriorityQueue 的几种构造方法:
构造方法

PriorityQueue 的方法:
PriorityQueue 的方法和其它数据结构类似:

PriorityQueue的方法

Top-k 问题: 最大或者最小的前k个数据。例如求一组数据中前 k 个最小的数据。

题目链接:leetcode----面试题 17.14. 最小K个数
题目描述:题目描述

思路一:我们可以初始化一个数组大小的堆,然后遍历数组的同时将元素放进堆中,默认是小根堆,所以取 k 次堆顶元素即可(删除堆顶元素后,会调整堆中的数据)。
代码:

public int[] smallestK(int[] arr, int k) {//存储最小K个数的数组int[] ret = new int[k];if (arr == null || k == 0) {return ret;}// 以数组长度初始化一个小根堆Queue<Integer> minHeap = new PriorityQueue<>(arr.length);//遍历数组  放进小根堆for (int value : arr) {minHeap.offer(value);}//取 k个堆顶元素for (int i = 0; i < k; i++) {ret[i] = minHeap.poll();}return ret;
}

上面这段代码会使时间复杂度升高,每添加或删除一个元素,就会调整一个接近数组长度的堆。

思路二:要求最小 k 个数,我们将数组里的前 k 个元素添加到一个大小为 k 的大根堆,因为是大根堆,所以堆顶元素是堆中最大的元素,然后遍历数组剩下的元素,如果数组剩下的元素比堆顶元素小,我们就删除堆顶元素,并添加数组的元素,如果数组剩下的元素比堆顶元素大,它就不会是前 k 个最小数。

代码:

public int[] smallestK(int[] arr, int k) {int[] ret = new int[k];if (arr == null || k == 0) {return ret;}//提供比较器,重写compare方法,此时建立的就是大根堆Queue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});//将数组前k个元素添加到大根堆中for (int i = 0; i < k; i++) {maxHeap.offer(arr[i]);}//遍历数组未添加到堆中的元素for (int i = k; i < arr.length; i++) {//因为是求最小值,所以如果比大根堆的堆顶元素小,就删除堆顶元素,并添加这个元素到堆中if (arr[i] < maxHeap.peek()) {maxHeap.poll();maxHeap.offer(arr[i]);}}//将堆中的k个元素添加中数组中for (int i = 0; i < k; i++) {ret[i] = maxHeap.poll();}return ret;
}

这段代码中,只建立了 k 个容量大小的堆,调整的个数就比第一段代码少。

对于求一组数据中前 k 个最大或最小的元素时,数据少时我们可以排序,但对于数据特别多时,还是采用堆的方式比较合适。步骤如下:

  1. 用数据集合中前K个元素来建堆。
    求前 k 个最大的元素,则建小堆
    求前 k 个最小的元素,则建大堆
  2. 用剩余的 N-K 个元素依次与堆顶元素来比较,不满足则替换堆顶元素,堆中剩余的 K 个元素就是所求的前 K 个最小或者最大的元素。

相关文章:

【数据结构】优先级队列----堆

优先级队列----堆优先级队列堆堆的创建堆的插入&#xff1a;堆的删除&#xff1a;PriorityQueue的特性PriorityQueue的构造与方法优先级队列 优先级队列&#xff1a; 不同于先进先出的普通队列&#xff0c;在一些情况下&#xff0c;优先级高的元素要先出队列。而这种队列需要提…...

Python深度学习实战PyQt5信号与槽的连接

本文讲解信号与槽的连接机制&#xff0c;详细示范各种类型的信号/槽连接的实现方法&#xff0c;这是图形用户界面的核心内容。还将介绍面向对象的程序设计&#xff0c;这是图形用户界面的基本思想目录1. 信号与槽&#xff08;Signals and slots&#xff09;信号与槽机制是 PyQt…...

Window 10 OpenCV 打开罗技(Logitech)摄像头速度慢问题解决

采用最新版OpenCV 4.7.0 摄像头对罗技摄像头进行视频图像抓取时&#xff0c;发现存在打开摄像头慢的问题。 测试环境如下&#xff1a; 系统Windows 10 专业版CPUIntel i7-7700K 4.20GHz 摄像头型号罗技Logitech C930c 网络摄像头OpenCV版本4.7.0语言C 测试结果表明&#xff…...

基于yolo的小球位置实时检测

基于yolo的小球位置实时检测 Yolo安装 操作系统&#xff1a;ubuntu 安装cuda和opencv git clone https://github.com/pjreddie/darknet.git cd darknet 修改Makefile文件&#xff0c;使GPU1&#xff0c;OPENCV1 make 2. 数据集处理 2.1 制作数据集 将小球放在摄像头前…...

【微服务】Elasticsearch数据聚合自动补全数据同步(四)

&#x1f697;Es学习第四站~ &#x1f6a9;Es学习起始站&#xff1a;【微服务】Elasticsearch概述&环境搭建(一) &#x1f6a9;本文已收录至专栏&#xff1a;微服务探索之旅 &#x1f44d;希望您能有所收获 在第二站的学习中&#xff0c;我们已经导入了大量数据到es中&…...

java面试题(十七)spring

2.1 请你说说Spring的核心是什么 参考答案 Spring框架包含众多模块&#xff0c;如Core、Testing、Data Access、Web Servlet等&#xff0c;其中Core是整个Spring框架的核心模块。Core模块提供了IoC容器、AOP功能、数据绑定、类型转换等一系列的基础功能&#xff0c;而这些功能…...

你知道 BI 是什么吗?关于 BI 系统的概述

BI 作为信息化建设中的关键一环&#xff0c;在企业中通常起到承上启下的作用&#xff0c;下能连接打通企业业务系统数据库&#xff0c;将各部门数据分类分级统一储存到数据仓库&#xff0c;简化存储取数流程&#xff0c;减少人力、时间成本&#xff1b;上能提供数据可视化报表…...

git:详解git rebase命令

背景 今天无意中打开 git 官网&#xff0c;发现 git 命令还是很多的&#xff0c;然而我们常用的就那几个&#xff0c;今天来学习一个也不怎么常用的命令 rebase 官网链接 都说学一个东西最好的方式就是读他的 官方文档&#xff0c;这里我读了一遍&#xff0c;把一些核心的地…...

第四章——随机变量的数字特征

文章目录1、数字特征的定义2、数学期望&#xff08;均值&#xff09;2.1、数学期望的定义及性质2.1.1、定义2.1.2、性质2.2、数学期望相关例题2.3、Yg(X)的数学期望2.4、Zg(X,Y)的数学期望2.5、随机变量函数的数学期望例题3、方差3.1、方差的定义与性质3.2、相关例题3.3、切比雪…...

vue2源码阅读理解-响应式数据原理

首先明确&#xff0c;vue2是如何实现响应式的&#xff1f; 通过object.defineProperty观察者模式实现&#xff0c;在创建vue实例的过程中&#xff0c;也就是介于beforecomputed~computed的过程中&#xff0c;会执行如下函数initState export function initState (vm: Componen…...

服务调用分布式session

目录一、nginx动静分离二、服务调用1、创建配置zmall-cart购物车模块2、创建配置zmall-order订单模块3、服务调用三、spring session实战1、什么是Spring Session2、为什么要使用Spring Session3、错误案例展示4、配置spring-session四、二级域名问题五、用户登录一、nginx动静…...

Maven知识点-插件-maven-surefire-plugin简介

Maven本身并不是一个单元测试框架&#xff0c;Java 世界中主流的单元测试框架为JUnit 和TestNG。 Maven 所做的只是在构建执行到特定生命周期阶段的时候&#xff0c;通过插件来执行JUnit或者TestNG的测试用例。 这一插件就是maven-surefire-plugin&#xff0c;可以称之为测试…...

如何借力Alluxio推动大数据产品性能提升与成本优化?

内容简介 随着数字化不断发展&#xff0c;各行各业数据呈现海量增长的趋势。存算分离将存储系统和计算框架拆分为独立的模块&#xff0c;Alluxio作为如今主流云数据编排软件之一&#xff0c;为计算型应用&#xff08;如 Apache Spark、Presto&#xff09;和存储系统&#xff0…...

linux shell脚本被包含是什么意思?.命令和source命令(在脚本中运行脚本,脚本中调用脚本)(脚本包含,父子脚本)

在 shell 编程中&#xff0c;当一个 shell 脚本被另一个 shell 脚本包含&#xff0c;即用 . 或 source 命令包含&#xff0c;则被包含的脚本在当前 shell 进程内执行&#xff0c;并且可以访问当前 shell 进程的环境变量和函数。 此时&#xff0c;$0 代表的是主脚本的名称&#…...

MySQL进阶篇之锁(lock)

05、锁 5.1、概述 1、介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据…...

TMDSEVM6657LS评估板恢复出厂默认状态

TMDSEVM6657LS评估板恢复出厂默认状态 前言 TMDSEVM6657LS评估板特别适用于DSP开发的初学者&#xff0c;但有时候拿到手的开发板几经流转&#xff0c;被别人修改过&#xff0c;也可能自己烧录过程出错&#xff0c;导致开发板的状态未知等原因&#xff0c;需要恢复到出厂默认状…...

聊一聊,我对DDD的关键理解

作者&#xff1a;闵大为 阿里业务平台解决方案团队 当我们在学习DDD的过程中&#xff0c;感觉学而不得的时候&#xff0c;可能会问&#xff1a;我们还要学么&#xff1f;这的确引人深思。本文基于工作经验&#xff0c;尝试谈谈对DDD的一些理解。 一、序 《阿甘正传》中&#xf…...

算法笔记(一)—— 认识复杂度和简单排序算法

时间复杂度是在一个算法流程中&#xff0c;常数操作的数量级指标。&#xff08;最差情况下的算法表现&#xff09; 比较两个算法的优劣&#xff0c;在足够的空间下&#xff0c;看时间复杂度指标&#xff0c;若相同&#xff0c;需要在大数据运行下来判断两个算法的“常数项指标…...

MQ消息中间件常见题及解决办法

目录儿常见MQRocketMQ2、RocketMQ测试可用MQ常见问题1、幂等性问题2、如何保证消息不丢失3、消息积压问题4、事务消息设计分析常见MQ RocketMQ RocketMQ又四部分组成 NameServer 同步Broker服务信息&#xff0c;给消费者和生产者提供可用Broker的服务信息。Broker 消息存储业…...

网关服务限流熔断降级分布式事务

目录一、网关服务限流熔断降级二、Seata--分布式事务1、分布式事务基础①事务②本地事物③分布式事务④分布式事务的场景2、分布式事务解决方案①全局事务②最大努力通知③TCC事务3、Seata介绍4、Seata实现分布式事务控制①案例基本代码&#xff08;异常模拟&#xff09;②启动…...

OpenMemories-Tweak完整指南:如何安全解锁索尼相机的隐藏功能

OpenMemories-Tweak完整指南&#xff1a;如何安全解锁索尼相机的隐藏功能 【免费下载链接】OpenMemories-Tweak Unlock your Sony cameras settings 项目地址: https://gitcode.com/gh_mirrors/op/OpenMemories-Tweak OpenMemories-Tweak是一款专为索尼相机设计的开源解…...

Comsol热流耦合拓扑优化:最大化放热量与功率耗散的探索

Comsol热流耦合拓扑优化。 目标函数采用最大化放热量和功率耗散。在工程领域&#xff0c;热流耦合问题一直是研究的重点&#xff0c;尤其是如何通过拓扑优化来实现特定目标&#xff0c;比如最大化放热量和功率耗散&#xff0c;这对于提高系统性能至关重要。而Comsol作为一款强大…...

如何快速上手TradingView图表库:15+框架完整集成实战指南

如何快速上手TradingView图表库&#xff1a;15框架完整集成实战指南 【免费下载链接】charting-library-examples Examples of Charting Library integrations with other libraries, frameworks and data transports 项目地址: https://gitcode.com/gh_mirrors/ch/charting-…...

AS3935闪电传感器Arduino驱动库深度解析与工业级应用

1. 项目概述AS3935 是一款由 AMS&#xff08;现为 ams OSRAM&#xff09;推出的专用闪电检测传感器芯片&#xff0c;集成 RF 前端、数字信号处理器&#xff08;DSP&#xff09;、闪电算法引擎及 IC/SPI 接口&#xff0c;可实现对 40 km 范围内云地闪&#xff08;CG&#xff09;…...

第10章 RTOS 感知调试(OpenOCD)

第10章 RTOS 感知调试 导读:在嵌入式开发中,RTOS(实时操作系统)的使用非常普遍。然而当多个线程并发执行时,传统的单线程调试方式无法感知任务切换和线程上下文,给问题定位带来极大困难。OpenOCD 内置了对十余种主流 RTOS 的线程感知调试支持,能够在暂停目标时自动识别所…...

Keil5实战:手把手教你制作自定义FLM插件(附完整驱动配置)

Keil5实战&#xff1a;手把手教你制作自定义FLM插件&#xff08;附完整驱动配置&#xff09; 在嵌入式开发领域&#xff0c;Flash编程算法&#xff08;FLM&#xff09;是连接开发环境与目标芯片闪存的重要桥梁。当我们需要支持非标准闪存芯片或特殊外设接口时&#xff0c;自定义…...

7-Zip ZS:六种压缩算法如何彻底改变你的文件处理体验

7-Zip ZS&#xff1a;六种压缩算法如何彻底改变你的文件处理体验 【免费下载链接】7-Zip-zstd 7-Zip with support for Brotli, Fast-LZMA2, Lizard, LZ4, LZ5 and Zstandard 项目地址: https://gitcode.com/gh_mirrors/7z/7-Zip-zstd 在数字时代&#xff0c;文件压缩已…...

开源像素艺术生成器落地实操:像素幻梦在独立游戏开发中的应用

开源像素艺术生成器落地实操&#xff1a;像素幻梦在独立游戏开发中的应用 1. 像素幻梦工具介绍 Pixel Dream Workshop&#xff08;像素幻梦创意工坊&#xff09;是一款基于FLUX.1-dev扩散模型的下一代像素艺术生成工具。与传统的AI绘图工具不同&#xff0c;它采用了明亮的16-…...

Twisted Protocols终极指南:快速构建高性能网络协议的简单方法

Twisted Protocols终极指南&#xff1a;快速构建高性能网络协议的简单方法 【免费下载链接】twisted Event-driven networking engine written in Python. 项目地址: https://gitcode.com/gh_mirrors/tw/twisted Twisted是一个用Python编写的事件驱动网络引擎&#xff0…...

brpc代码重构原则:保持兼容性与提升性能并重的终极指南

brpc代码重构原则&#xff1a;保持兼容性与提升性能并重的终极指南 【免费下载链接】brpc brpc is an Industrial-grade RPC framework using C Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recomme…...