Java 数据结构篇-实现堆的核心方法与堆的应用(实现 TOP-K 问题:最小 k 个数)
🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍
文章目录
1.0 堆的说明
2.0 堆的成员变量及其构造方法
3.0 实现堆的核心方法
3.1 实现堆的核心方法 - 获取堆顶元素 peek()
3.2 实现堆的核心方法 - 下潜 down(int i)
3.3 实现堆的核心方法 - 交换元素 swap(int i,int j)
3.4 实现堆核心方法 - 删除堆顶元素 poll()
3.5 实现堆的核心方法 - 替换堆顶元素 replace(int i)
3.6 实现堆的核心方法 - 添加元素 offer(int value)
3.7 实现堆的核心方法 - 建堆 heapify()
3.8 实现堆的核心方法完整代码
4.0 TOP - K 问题:最小的 K 个数
4.1 实现最小 k 个数的思路
4.2 代码实现最小 k 个数
1.0 堆的说明
堆(Heap)是一种基于树的数据结构,通常用于动态分配内存空间。堆可以被看作是一棵完全二叉树,其中每个节点都满足堆的性质,即父节点的值大于或等于子节点的值(大根堆),或父节点的值小于或等于子节点的值(小根堆)。在堆中,根节点的值是最大或最小的,因此也被称为最大堆或最小堆。
堆的实现通常使用数组来存储堆中的元素,通过计算数组下标来实现节点之间的关系。堆的时间复杂度为 O(log n),其中 n 是堆中元素的数量。
堆的操作包括插入、删除和查找等。插入操作将一个新元素插入到堆中,删除操作将堆中的最大或最小元素删除,查找操作可以在堆中查找特定元素的位置。
2.0 堆的成员变量及其构造方法
主要的成员变量为:int[] arr 数组:用来存放元素的容器;int size :代表当前的元素个数。
构造方法:指定数组大小带参数的构造器、参数为数组的构造器。
代码如下:
public class MyHeap {public int[] arr;public int size;public MyHeap(int capacity) {arr = new int[capacity];}public MyHeap(int[] arr) {this.arr = arr;this.size = arr.length;heapify();}}
3.0 实现堆的核心方法
获取堆顶元素、下潜、交换元素、添加元素、替换元素、删除元素、建堆。
3.1 实现堆的核心方法 - 获取堆顶元素 peek()
用数组实现堆,在获取堆顶元之前,先需要判断该数组是否为空,若不为空,则直接返回数组索引为 0 的元素;若数组为空,则返回 0 或者抛出异常也可以。
代码如下:
//获取栈顶元素public int peek() {if (isEmpty()) {return -1;}return arr[0];}
3.2 实现堆的核心方法 - 下潜 down(int i)
该方法主要用于删除栈顶元素、替换元素等核心方法。下潜的意思就是将当前的元素所在的位置不符合大顶堆或者小顶堆的规则,因此需要向下调整。找到合适的位置来存放当前的元素。
具体下潜的思路:
假设需要满足大顶堆的规则:
由以上的图来看,当前的索引为 0 处的元素 7 小于该左孩子的元素,因此当前不满足大顶堆的规则。需要将两者进行交换。
交换的结果为:
交换完之后,当前索引为 2 处的元素 7 小于该右孩子的元素,所以索引 2 与 索引 5 需要继续交换。若当前为 i 该右孩子的索引 left = 2 * i + 1;该左孩子的索引 right = 2 * i + 2 (也可以表示为 right = left + 1 )一开始默认当前的最大元素的索引 max = i ,接着来判断该左右孩子的元素是否大于当前索引 max ,若大于当前索引 max 时,需要进行交换 max = left 或者 max = right 。若不大于当前索引为 max 处的元素,则不需要交换。由于每一次都是子问题过程,所以可以利用递归来实现,当且仅当 max != i 时,说明 max 已经被交换过了,需要继续向下递出,直到 max == i 时,结束递出,开始回溯。当然,这里不需要回带任何值或者变量,即该递归函数的返回类型为 viod 。
代码如下:
//下潜public void down(int i) {int left = 2 * i + 1;int right = left + 1;int max = i;if (left < size && arr[left] > arr[max]) {max = left;}if (right < size && arr[right] > arr[max]) {max = right;}if (max != i) {//交换swap(i,max);//继续下潜down(max);}}
3.3 实现堆的核心方法 - 交换元素 swap(int i,int j)
交换数组索引中 i 与 j 处的元素。
代码如下:
//交换public void swap(int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}
3.4 实现堆核心方法 - 删除堆顶元素 poll()
具体实现思路:为了更高效率的删除堆顶元素后保持原来大顶堆或者小顶堆的规则。
步骤一:先将堆顶元素与最后一个元素进行交换。即 arr[0] = arr[size - 1] 。
步骤二:将 size-- 。
步骤三:交换后的堆,可能会不满足大顶堆或者小顶堆的规则,则需要将堆顶元素进行下潜调整,找到合适的位置存放该元素。最后需要返回删除的元素。
代码如下:
//删除堆顶元素public int poll() {if (isEmpty()) {return 0;}int t = arr[0];arr[0] = arr[size - 1];size--;//下潜down(0);return t;}
注意:在删除堆顶元素之前,需要先判断当前的数组是否为空数组。
同理,若需要删除指定堆中的元素索引,实现思路是一样的。
代码如下:
//指定删除元素public int poll(int i) {if (i > size) {return 0;}int temp = arr[i];arr[i] = arr[size - 1];size--;//下潜down(i);return temp;}
先判断索引是否合法,若不合法,则返回 0 或者抛出异常也可以。
3.5 实现堆的核心方法 - 替换堆顶元素 replace(int i)
具体思路为:先判断该数组是否为空数组,若不为空数组,则直接替换堆顶元素 arr[0] = i;之后可能会不满足大顶堆或者小顶堆的规则,所以索引为 0 处需要下潜调整,找到合适的位置存放元素。
代码实现:
//替换堆顶元素public void replace(int i) {if (isEmpty()) {return;}arr[0] = i;down(0);}
3.6 实现堆的核心方法 - 添加元素 offer(int value)
具体实现思路:先判断当前索引为 i = size 处的双亲节点为 j = (i - 1) / 2 ,判断 arr[j] 与 value 的大小,若为大顶堆规则,则当 arr[j] > value 时,不需要继续往上走了,在 i 处存放 value 即可 arr[i] = value ;当 arr[j] <= value 时,先将 arr[j] 处的元素存放在 arr[i] 中,接着需要继续往上走, i = j ,j = (i - 1) / 2 直到 i == 0 或者 arr[j] > value 时,退出循环。在 arr[i] 处存放 value 。
代码如下:
//添加元素public boolean offer(int value) {if (isFull()) {return false;}int i = size;int j = (size - 1) / 2;while (i > 0 && arr[j] < value) {arr[i] = arr[j];i = j;j = (i - 1) / 2;}arr[i] = value;size++;return true;}
需要注意:添加元素前,需要先判断该数组是否满了。还有添加完之后,需要进行 size++ 。
3.7 实现堆的核心方法 - 建堆 heapify()
该方法实现的意义,若随机给出一个数组,需要实现由大顶堆或者小顶堆的结构存放元素。因此就会用到该方法。
实现思路为:需要找到最后一个非叶子节点,从后往前,将当前的元素进行下潜处理即可完成建堆。
代码如下:
//建堆public void heapify() {//先找到最后非叶子节点int lastNonLeafNodes = size / 2 - 1;for (int i = lastNonLeafNodes; i >= 0 ; i--) {//下潜down(i);}}
3.8 实现堆的核心方法完整代码
public class MyHeap {public int[] arr;public int size;public MyHeap(int capacity) {arr = new int[capacity];}public MyHeap(int[] arr) {this.arr = arr;this.size = arr.length;heapify();}//获取栈顶元素public int peek() {if (isEmpty()) {return -1;}return arr[0];}//删除堆顶元素public int poll() {if (isEmpty()) {return 0;}int t = arr[0];arr[0] = arr[size - 1];size--;//下潜down(0);return t;}//指定删除元素public int poll(int i) {if (i > size) {return 0;}int temp = arr[i];arr[i] = arr[size - 1];size--;//下潜down(i);return temp;}//替换堆顶元素public void replace(int i) {if (isEmpty()) {return;}arr[0] = i;down(0);}//添加元素public boolean offer(int value) {if (isFull()) {return false;}int i = size;int j = (size - 1) / 2;while (i > 0 && arr[j] < value) {arr[i] = arr[j];i = j;j = (i - 1) / 2;}arr[i] = value;size++;return true;}//建堆public void heapify() {//先找到最后非叶子节点int lastNonLeafNodes = size / 2 - 1;for (int i = lastNonLeafNodes; i >= 0 ; i--) {//下潜down(i);}}//下潜public void down(int i) {int left = 2 * i + 1;int right = left + 1;int max = i;if (left < size && arr[left] > arr[max]) {max = left;}if (right < size && arr[right] > arr[max]) {max = right;}if (max != i) {//交换swap(i,max);//继续下潜down(max);}}//交换public void swap(int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}//判断是否为空数组public boolean isEmpty() {return size == 0;}//判断是否为满数组public boolean isFull() {return size == arr.length;} }
4.0 TOP - K 问题:最小的 K 个数
题目:
设计一个算法,找出数组中最小的k个数。以任意顺序返回这 k 个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4 输出: [1,2,3,4]提示:
0 <= len(arr) <= 100000
0 <= k <= min(100000, len(arr))
OJ 链接:
面试题 17.14. 最小K个数
4.1 实现最小 k 个数的思路
具体思路为:结合大顶堆的数据结构的特点,根节点的元素永远比孩子节点的元素大。先将给定的 arr 数组的前 k 个元素直接通过 heap.offer() 方法添加到大顶堆上,然后 arr 数组剩下的元素需要跟堆顶元素相对比,若堆顶元素大于 arr[i] 中的元素,则需要进行交换,将 arr[i] 的元素替换到堆顶,接着还不能结束,有可能替换完的元素就不符合大顶堆的规则了,因此还需要将堆顶元素下潜处理调整,找到合适的位置存放该元素;若堆顶元素不大于 arr[i] 中的元素,则不需要交换。一直将 arr 数组中的元素遍历结束,则循环停止。最后堆上存储的 k 个元素就是该数组 arr 中最小的元素了。
4.2 代码实现最小 k 个数
public class Solution {public int[] smallestK(int[] arr, int k) {MaxHeap heap = new MaxHeap(k);for(int i = 0; i < k ; i++) {heap.offer(arr[i]);}for(int i = k; i < arr.length; i++) {if(heap.peek() > arr[i]) {heap.arr[0] = arr[i];heap.down(0);}}return heap.arr;}}//实现一个大顶堆 class MaxHeap {int[] arr;int size;public MaxHeap(int capacity) {arr = new int[capacity];}public MaxHeap(int[] smallestK) {this.arr = smallestK;this.size = smallestK.length;}//插入元素public boolean offer(int value) {if(isFull()) {return false;}int i = size;int j = (i - 1) / 2;while(i > 0 && arr[j] < value) {arr[i] = arr[j];i = j;j = (i - 1) / 2;}arr[i] = value;size++;return true;}//删除堆顶元素public int poll() {if(isEmpty()) {return 0;}int ret = arr[0];arr[0] = arr[size - 1];size--;down(0);return ret;}//下潜public void down(int i) {int left = 2 * i + 1;int right = left + 1;int max = i;if(left < size && arr[left] > arr[max]) {max = left;}if(right < size && arr[right] > arr[max]) {max = right;}if(max != i) {swap(max,i);down(max);}}//交换public void swap(int i, int j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}//获取堆顶元素public int peek() {if(isEmpty()) {return 0;}return arr[0];}//判断是否为空public boolean isEmpty() {return size == 0;}//判断是否为满public boolean isFull() {return size == arr.length;}}
相关文章:

Java 数据结构篇-实现堆的核心方法与堆的应用(实现 TOP-K 问题:最小 k 个数)
🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 堆的说明 2.0 堆的成员变量及其构造方法 3.0 实现堆的核心方法 3.1 实现堆的核心方法 - 获取堆顶元素 peek() 3.2 实现堆的核心方法 - 下潜 down(int i) 3.3 实…...
startUML6.0.1破解方法
startUML6.0.1破解方法 文章目录 startUML6.0.1破解方法1.startUML6.0.1快速破解2.概述3.安装Nodejs4.安装asar5.修改app.asar中的源码6.将修改后的源码重新压缩7.覆盖官方的asar文件8.重启startUML9.参考文档 1.startUML6.0.1快速破解 后绪步骤可以不看,直接下载我…...
Python实现多种图像分割方法:基于阈值分割和基于区域分割
Python实现多种图像分割方法:基于阈值分割和基于区域分割 图像分割是图像分析的第一步,是计算机视觉的基础,但也是图像处理中最困难的问题之一。经典的计算机视觉任务,如目标检测、图像识别等都和图像分割相关,图像分…...

SQL学习笔记+MySQL+SQLyog工具教程
文章目录 1、前言2、SQL基本语言及其操作2.1、CREATE TABLE – 创建表2.2、DROP TABLE – 删除表2.3、INSERT – 插入数据2.4、SELECT – 查询数据2.5、SELECTDISTINCT – 去除重复值后查询数据2.6、SELECTWHERE – 条件过滤2.7、AND & OR – 运算符2.8、ORDER BY – 排序2…...

SpringBoot的日志管理
🙈作者简介:练习时长两年半的Java up主 🙉个人主页:程序员老茶 🙊 ps:点赞👍是免费的,却可以让写博客的作者开心好久好久😎 📚系列专栏:Java全栈,…...

leetcode---76. 最小覆盖子串 [C++/滑动窗口+哈希表]
原题:76. 最小覆盖子串 - 力扣(LeetCode) 题目解析: 此题在这道题的基础上进行理解会更简单 leetcode --- 30. 串联所有单词的子串[C 滑动窗口/双指针]-CSDN博客 本题要求在s字符串中找到含有t字符串所有字符的最短子串。 也就是…...

Kafka 分级存储在腾讯云的实践与演进
导语 腾讯云消息队列 Kafka 内核负责人鲁仕林为大家带来了《Kafka 分级存储在腾讯云的实践与演进》的精彩分享,从 Kafka 架构遇到的问题与挑战、Kafka 弹性架构方案类比、Kafka 分级存储架构及原理以及腾讯云的落地与实践四个方面详细分享了 Kafka 分级存储在腾讯云…...

域架构下的功能安全思考
来源:联合电子 随着整车电子电气架构的发展,功能域控架构向整车集中式区域控制演进。新的区域控制架构下,车身控制模块(BCM),整车控制单元(VCU),热管理系统(TMS)和动力底…...
python多线程介绍
每个库或模块都有其特定的用途和优势,选择哪一个取决于具体的任务需求、计算资源。一般可以将任务分成两类: I/O 密集型任务:这些任务的瓶颈主要在于等待外部操作,如磁盘读写或网络通信。在这些等待期间,CPU 大部分时间…...

征文榜单 | 腾讯云向量数据库获奖名单公布
为了帮助开发者更快、更便捷地构建应用程序,有效提高开发人员生产力,腾讯云推出了AI原生向量数据库。它能提供全托管的自研企业级分布式数据库服务,专用于存储、检索、分析多维向量数据,是国内首个从接入层、计算层、到存储层提供…...

如何预防[[MyFile@waifu.club]].wis [[backup@waifu.club]].wis勒索病毒感染您的计算机?
导言: 近期,一种新兴的威胁[[MyFilewaifu.club]].wis [[backupwaifu.club]].wis勒索病毒,引起了广泛关注。这种恶意软件通过其高度复杂的加密算法,威胁着用户和组织的数据安全。本文将深入介绍[[MyFilewaifu.club]].wis [[backup…...

中国风春节倒计时【实时倒计时】
<head><meta charset="UTF-8"><meta name="apple-mobile-web-app-title...
基于RBAC的k8s集群权限管控案例
在日常的kubernetes集群维护过程中,常常涉及多团队协作,不同的团队有不同的操作和权限需求。比如,运维团队需要有node的所有操作权限,以便对集群进行节点的扩缩容等日常维护工作,但资产运营团队通常只需要node的查看权…...
【华为数据之道学习笔记】5-11 算法模型设计
算法是指训练、学习模型的具体计算方法,也就是如何求解全局最优解,并使得这个过程高效且准确,其本质上是求数学问题的最优化解,即算法是利用样本数据生成模型的方法。算法模型是根据业务需求,运用数学方法对数据进行建…...
Flink系列之:SELECT WHERE clause
Flink系列之:SELECT & WHERE clause 一、SELECT & WHERE clause二、SELECT DISTINCT 适用于流、批 一、SELECT & WHERE clause SELECT 语句的一般语法是: SELECT select_list FROM table_expression [ WHERE boolean_expression ]table_e…...
C#基础——委托、Action和Func的使用
1、委托 委托(Delegate)是一种类型,可以用来表示对一个或多个方法的引用。委托提供了一种方便的方式来将方法作为参数传递给其他方法,或将方法存储在数据结构中以供以后调用。 不带参数且没返回值的委托 delegate void HDLDelega…...

不止业务缓存,分布式系统中还有哪些缓存?
缓存是分布式系统开发中的常见技术,在分布式系统中的缓存,不止 Redis、Memcached 等后端存储;在前端页面、浏览器、网络 CDN 中也都有缓存的身影。 缓存有哪些分类 如果你是做业务开发的话,提起缓存首先想到的应该是应用 Redis&…...

Java 基础学习(十三)集合框架、List集合
1 集合框架 1.1 Collection 1.1.1 集合框架概述 Java 集合框架是一组实现了常见数据结构(如列表、树集和哈希表等)的类和接口,用于存储一组数据。 开发者在使用Java的集合类时,不必考虑数据结构和算法的具体实现细节ÿ…...
el-select二次封装实现可分页加载数据
使用el-select时一次性渲染几百条数据时会造成页面克顿, 可以通过分页来实现, 这里我用的方式为默认获取全部数据, 然后一次性截取10条进行展示, 滚动条触底后会累加, 大家也可以优化为滚动条触底后发送请求去加载数据 创建自定义指令customizeFocus用户懒加载 在utils文件夹(…...

css实现0.5px宽度/高度显——属性: transform: scale
在大多数设备上,实际上无法直接使用 CSS 来精确地创建 0.5 像素的边框。因为大多数屏幕的最小渲染单位是一个物理像素,所以通常只能以整数像素单位渲染边框。但是,有一些技巧可以模拟出看起来像是 0.5 像素的边框。 这里介绍使用:…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...