堆 和 优先级队列

目录

一、堆

二、优先级队列 

1、初识优先级队列 

2、实现一个优先级队列 

3、PriorityQueue 

(1)实现了Comparable接口,重写了compareTo方法

(2)实现了Comparator接口,重写了compare方法

4、 PriorityQueue 的应用

Top-k问题:使用 PriorityQueue 来做


一、堆

  1. 堆 是一种数据结构,是在完全二叉树的基础上进行了一些调整。
  2. 堆 分为大根堆 和 小根堆,根结点比左右结点都大的堆叫做 大根堆,根结点比左右结点都小的堆叫小根堆。
  3. 堆 的存储结构(物理结构):顺序存储,即会有一个数组,按照层序的方式顺序存储
  4. 若 父结点下标为 i,则左孩子下标为 2*i+1,右孩子下标为2*i+2;若 子结点下标为 i,则父结点下标为 (i-1)/2

二、优先级队列 

1、初识优先级队列 

优先级队列(PriorityQueue)底层是小根堆。

2、实现一个优先级队列 

采用顺序存储的结构,使用数组来实现。

建堆的两种方法:建堆的时间复杂度是O(n) 

1、先给elem数组赋值,创建一棵完全二叉树。然后从最后一棵子树的根结点开始调整,将每棵子树都调整成小根堆。调整的方案是向下调整(shiftDown)

shiftDown的时间复杂度:O(log n)

2、从无到有,不先创建完全二叉树,而是每放一个数据,都需要调整成小根堆。调整的方案是向上调整(shiftUp)

shiftUp的时间复杂度: O(log n)

对于优先级队列来说,入队和出队的时间复杂度 O(log n)  

import java.util.Arrays;//底层是小根堆
public class MyPriorityQueue {public int[] elem;public int size;//数组的有效长度public static final int DEFAULT_SIZE = 10;public MyPriorityQueue(){this.elem = new int[10];}/*** 2、建堆第二种方法:从无到有,不先创建完全二叉树,而是每放一个数据,都需要调整成小根堆。*/public void createHeap2(int data){if(isEmpty()){elem[0] = data;size++;return;}if(isFull()){elem = Arrays.copyOf(elem,elem.length*2);}elem[size] = data;size++;shiftUp(size-1);}/*** 1、建堆第一种方法:先给elem数组赋值,创建一棵完全二叉树。然后从最后一棵子树的根结点开始调整,将每棵子树都调整成小根堆。*///给数组赋值,创建了一棵完全二叉树public void createTree(int[] arr){for (int i = 0; i < arr.length; i++) {this.elem[i] = arr[i];this.size++;}}//将完全二叉树调整成小根堆public void createHeap(){//从最后一个根结点开始往前调整int parent = ((size-1)-1)/2;for (int i = parent; i >= 0 ; i--) {shiftDown(i);}}//将根为parent的树调整为小根堆public void shiftDown(int parent){int child = 2*parent+1;while(child < size){//child+1 < size 保证有右树if(child+1 < size && elem[child+1] < elem[child]){child++;}//走到这,child 是左右子树最小值的下标if(elem[child] < elem[parent]){swap(child,parent);parent = child;child = 2*parent+1;}else{break;}}}public void swap(int x,int y){int tmp = elem[x];elem[x] = elem[y];elem[y] = tmp;}//入队:时间复杂度 O(log n)public void offer(int data){if(isFull()){elem = Arrays.copyOf(elem,elem.length*2);}elem[size] = data;size++;shiftUp(size-1);}public boolean isFull(){return size == this.elem.length;}public void shiftUp(int child){int parent = (child-1)/2;while(child > 0){if(elem[child] < elem[parent]){swap(child,parent);child = parent;parent = (child-1)/2;}else{break;}}}//出队:时间复杂度 O(log n)public int poll(){if(isEmpty()){return -1;}int delete = elem[0];swap(0,size-1);size--;//这样就只需要将parent=0的这棵树调整为小根堆就行了shiftDown(0);return delete;}public boolean isEmpty(){return size == 0;}//获取队顶元素但不删除public int peek(){if(isEmpty()){return -1;}return elem[0];}}

3、PriorityQueue 

  1. PriorityQueue 底层是小根堆。
  2. PriorityQueue 没有传数组容量时,默认的初始容量是11;如果传容量,不能<1,否则
    会抛 IllegalArgumentException 异常
  3. PriorityQueue 放入的数据必须得能比较大小,即插入的数据要么实现了Comparable<T>接口,要么 实现了Comparator<T>接口,否则会抛出 ClassCastException异常
  4. PriorityQueue 放入的数据如果实现了比较器,要把比较器传过去,优先使用比较器来比较
  5. PriorityQueue 不能插入null对象,否则会抛出NullPointerException异常
  6. PriorityQueue 底层会自动扩容,容量<64时会2倍扩容,容量>=64时会1.5倍扩容

(1)实现了Comparable<T>接口,重写了compareTo方法

import java.util.PriorityQueue;
class Student implements Comparable<Student>{public int age;public Student(int age){this.age = age;}@Overridepublic int compareTo(Student o) {return this.age - o.age;}
}
public class Test {public static void main(String[] args) {PriorityQueue<Student> priorityQueue = new PriorityQueue<>();priorityQueue.offer(new Student(20));priorityQueue.offer(new Student(10));priorityQueue.offer(new Student(30));System.out.println();}
}

 

我们发现,数据确实有序了,而且是小根堆的形式。当然,我们也可以把它变成大根堆。

我们将  return this.age - o.age;改成 return o.age - this.age; 后,就变成了大根堆的形式。

(2)实现了Comparator<T>接口,重写了compare方法

那么,Integer怎么变成大根堆形式呢,Integer的compareTo方法是在源码里写好的,我们改不了源码。于是就用到了比较器,传个比较器过去,在比较器里重写compare方法,就可以改了。

class IntCmp implements Comparator<Integer>{@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}
}
public class Test {public static void main(String[] args) {PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new IntCmp());priorityQueue.offer(20);priorityQueue.offer(10);priorityQueue.offer(30);System.out.println();}
}

 

我们将  return o1.compareTo(o2);改成return o2.compareTo(o1);后,就变成了大根堆的形式。

4、 PriorityQueue 的应用

Top-k问题:使用 PriorityQueue 来做

求最的前k个元素或第k大的元素,就 将前 k 个数建立成小根堆;

求最的前k个元素或第k小的元素,就 将前 k 个数建立成大根堆。

时间复杂度:n*log k(堆的大小是k,数组中元素的个数是n)

(1)数据集合中最大或最小的前k个元素(一般情况下,数据量都会非常大。)

如:找出数组中最小的k个数,以任意顺序返回这k个数均可。 

解题思路: 

  1. 将前 k 个数建立成大根堆
  2. 从第 k+1 个数据开始,每次都和堆顶元素比较,如果比堆顶元素小,就弹出堆顶元素,把这个元素放进堆
  3. 那么最后,堆中的这k个元素就是数组中最小的k个数

为什么找 最小的k个数 要建大根堆呢?

因为,大根堆的堆顶元素是最大的,

若后面的数据比它大,说明肯定不属于 最小的k个数;若后面的数据比它小,说明它肯定不属于 最小的k个数,那么就把它弹出,把这个数据放进去。以此类推。最后这个k大小的堆中就是最小的k个数了。

 //找出数组中最小的k个数public static int[] topK(int[] arr,int k){if(arr == null || k == 0) {return new int[0];}PriorityQueue<Integer> min = new PriorityQueue<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2.compareTo(o1);}});for (int i = 0; i < k; i++) {min.offer(arr[i]);}//到这里,建了一个大小为3的 大根堆for (int i = k; i < arr.length; i++) {int peek = min.peek();if(arr[i] < peek){min.poll();min.offer(arr[i]);}}//走到这,min 里就是数组中最小的k个数int[] tmp = new int[k];for (int i = 0; i < k; i++) {tmp[i] = min.poll();}return tmp;
}

(2)第k小/第k大的元素

如:找出数组中第k小的元素

解题思路:

  1. 将前 k 个数建立成大根堆
  2. 从第 k+1 个数据开始,每次都和堆顶元素比较,如果比堆顶元素小,就弹出堆顶元素,把这个元素放进堆
  3. 那么最后,堆顶元素就是第k小的元素
//找出数组中第k小的数public static int least(int[] arr,int k){if(arr == null || k == 0) {return -1;}PriorityQueue<Integer> min = new PriorityQueue<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2.compareTo(o1);}});for (int i = 0; i < k; i++) {min.offer(arr[i]);}//到这里,建了一个大小为3的 大根堆for (int i = k; i < arr.length; i++) {int peek = min.peek();if(arr[i] < peek){min.poll();min.offer(arr[i]);}}//走到这,min 里就是数组中最小的k个数return min.peek();
}

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

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

相关文章

Django+Celery框架自动化定时任务开发

本章介绍使用DjCelery即DjangoCelery框架开发定时任务功能&#xff0c;在Autotestplat平台上实现单一接口自动化测试脚本、业务场景接口自动化测试脚本、App自动化测试脚本、Web自动化测试脚本等任务的定时执行、调度、管理等&#xff0c;从而取代Jenkins上的定时执行脚本和发送…

windows安装Redis,Mongo,ES并快速基本掌握开发流程

前言 这里只是一些安装后的基础操作&#xff0c;后期会学习更加深入的操作 基础操作 前言RedisRedis启动idea集成Redisjedis技术 Mongodbwindows版Mongodb的安装idea整合Mongodb ES(Elasticsearch)ESwindows下载ES文档操作idea整合ES低级别ES整合高级别ES整合 Redis Redis是…

深入理解JVM后端优化技术-方法内联

相关系列 深入理解JVM后端优化技术-逃逸分析(Escape Analysis)-CSDN博客 深入理解JVM后端优化技术-锁消除&#xff08;Lock Elision)-CSDN博客 深入理解JVM后端优化技术-锁粗化(Lock Coarsening)-CSDN博客 jvm只是负责依次将字节码指令逐次转换成机器码。而在转换过程中&#x…

【THM】Net Sec Challenge(网络安全挑战)-初级渗透测试

介绍 使用此挑战来测试您对网络安全模块中获得的技能的掌握程度。此挑战中的所有问题都可以仅使用nmap、telnet和来解决hydra。 挑战问题 您可以使用Nmap、 Telnet 和Hydra回答以下问题。 2.1小于10000的最大开放端口号是多少? 8080 nmap -p- -T4 10.10.234.218 2.2普通…

gurobi不同版本切换

每年年底&#xff0c;gurobi都会推出新版本。新版本是大的迭代更新&#xff0c;求解问题的效率和精度都会提升。官方人员一般会建议我们安装最新的版本&#xff0c;此外&#xff0c;写论文审稿专家也会建议我们使用较新的版本。 从我们现装的版本切换到新版本。我以往的做法是…

接口自动化测试利器,使用Rest Assured进行REST API测试

我们在做接口测试时&#xff0c;一般在代码中会使用HttpClient&#xff0c;但是HttpClient相对来讲还是比较麻烦的&#xff0c;代码量也相对较多&#xff0c;对于新手而言上手会比较难一点&#xff0c;今天我们来看下另一个接口测试工具包REST Assured REST Assured是一个流行…

麒麟V10安装Redis6.2.6

1、下载redis安装包 Redis各版本下载&#xff1a;https://download.redis.io/releases/ 2、将下载后的.tar.gz压缩包上传到到服务器自定义文件夹下 3、 解压文件 tar -zxvf redis-6.2.6.tar.gzmv redis-6.2.6 redis4、安装redis 在redis文件夹下输入make指令 cd /opt/redi…

MoCo 算法阅读记录

论文地址&#xff1a;&#x1f430; 何凯明大神之作&#xff0c;通过无监督对比学习预训练Image Encoder的表征能力。后也被许多VLP算法作为ITC的底层算法来使用。 一方面由于源代码本身并不复杂&#xff0c;但是要求多GPU分布式训练&#xff0c;以及需要下载ImageNet这个大规模…

Ubuntu 20.04.06 PCL C++学习记录(二十一)【切记使用rm * -rf前先确认是否是对应文件夹】

[TOC]PCL中点云分割模块的学习 学习背景 参考书籍&#xff1a;《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,&#xff0c;PCL版本为1.10.0&#xff0c;CMake版本为3.16&#xff0c;测试点云下载地址 学习内容 根据欧几里得距离和需要保持的用户可自定义条件对点进…

【分析 GClog 的吞吐量和停顿时间、heapdump 内存泄漏分析】

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容GClog分析以优化吞吐量和停顿时间步骤1: 收集GClog步骤2: 分析GClog步骤3: 优化建议步骤4: 实施优化 Heapdump内存泄漏分析步骤1: 获取Heapdump步骤2: 分析Heapdump步骤3: 定位泄漏对象步骤4: 分析泄漏原因步骤5: 修复泄漏…

预训练的启蒙:浅谈BERT、RoBERTa、ALBERT、T5

文章目录 Transformer揭开预训练序幕为什么RNN/LSTM需要从头训练&#xff1f; BERT核心特点预训练任务架构应用和影响 RoBERTa改进点BERT和RoBERTa的MASK策略对比BERT的静态MASK策略RoBERTa的动态MASK策略效果 总结 ALBERT改进点参数共享因式分解嵌入参数和LoRa对比 总结 T5核心…

Electron打包vue+java+nginx 踩坑记录

记录下遇到的问题&#xff1a; ⚠注意&#xff1a;64位系统和32位系统的配置不太一样 1、运行npm run packager失败 原因&#xff1a;在package.json没有对应命令 解决&#xff1a;在package.json 中添加对应命令&#xff0c;其中testApp是你想要的输入的项目名称&#xff0…

element用户上传头像组件带大图预览,和删除功能

element 用户上传组件不支持大图预览&#xff0c;拿组件的简单修改一些&#xff0c;发表上来主要是记一下&#xff0c;以后可以用 效果图 <template><div class"flex-img"><div class"el-upload-list el-upload-list--picture-card" v-sh…

word从零基础到高手【办公】

第1课 - word基础操作快速入门第2课 - 让你效率10倍提升的快捷操作第3课 - word排版快速入门第4课 - 排版实战案例讲解第5课 - 搞定论文排版全过程第6课 - 让你的word更强大的神技第7课 - 提高工作效率必备的批量操作 资料截图如下: 发送: "word办公" 获取提取码

动态规划-入门理解

一、什么情况可以使用动态规划 动态规划 最优子结构 重叠子问题 转移方程 最优子结构&#xff1a;保证能从局部解推出全局解&#xff0c;也就是保证能够写出转移方程 重叠子问题&#xff1a;说明暴力解法太耗时&#xff0c;我们可以使用动态规划进行优化 转移方程&#xff…

基于GAN的图像补全实战

数据与代码地址见文末 论文地址:http://iizuka.cs.tsukuba.ac.jp/projects/completion/data/completion_sig2017.pdf 1.概述 图像补全,即补全图像中的覆盖和缺失部分, 网络整体结构如下图所示,整体网络结构还是采取GAN,对于生成器,网络结构采取Unet的形式,首先使用卷积…

rac数据库默认网关不通导致集群异常

集群CSSD进程reconfiguration完成&#xff0c;显示2个节点都在线。但ora.net1.network服务启动失败&#xff0c;且有依赖关系的资源随后启动失败并且已经达到上限。 查看两个节点的网络信息&#xff0c;发现两个节点的默认网关是不一致的。 修改故障节点网关 在RAC中&#xff0…

基于springboot+vue+Mysql的职称评审管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

在线人数统计功能怎么实现?

一、前言 大家好&#xff01;我是sum墨&#xff0c;一个一线的底层码农&#xff0c;平时喜欢研究和思考一些技术相关的问题并整理成文&#xff0c;限于本人水平&#xff0c;如果文章和代码有表述不当之处&#xff0c;还请不吝赐教。 在线人数统计这个功能相信大家一眼就明白是…

基于奇异值分解(Singular Value Decomposition,SVD)的信号去噪算法

01.基于奇异值分解(SVD)去噪原理 奇异值分解&#xff08;Singular Value Decomposition, SVD&#xff09;是线性代数中一种重要的矩阵分解方法&#xff0c;它可以用于信号处理、图像去噪、数据压缩等多种应用。在图像去噪的过程中&#xff0c;SVD可以用来分离图像中的信号和噪…