利用编程思维做题之最小堆选出最大的前10个整数
1. 理解问题
我们需要设计一个程序,读取 80,000 个无序的整数,并将它们存储在顺序表(数组)中。然后从这些整数中选出最大的前 10 个整数,并打印它们。要求我们使用时间复杂度最低的算法。
由于数据量很大,直接排序的时间复杂度较高,因此我们需要一个更高效的算法。最小堆 是一种合适的选择,因为它能够在 O(n log k) 的时间复杂度内完成最大 10 个整数的选取。
2. 输入输出
- 输入:通过键盘输入 80,000 个整数。
- 输出:打印出最大的 10 个整数。
3. 数据结构
我们使用一个最小堆来存储当前最大 10 个数。堆的根节点是堆中最小的元素,插入新元素时,如果新元素大于堆的根节点,则替换根节点并调整堆结构。这样,在遍历完所有 80,000 个数之后,堆中的 10 个元素就是最大的 10 个整数。
最小堆的数据结构如下:
struct MinHeap {
int* arr; // 存储堆的数组
int size; // 当前堆的大小
int capacity; // 堆的最大容量
};
4. 制定策略
- 建堆:我们通过一个大小为 10 的最小堆来存储当前最大的 10 个数。
- 遍历输入:每读取一个数,检查该数是否大于堆顶元素,如果大于,则替换堆顶并调整堆。
- 输出结果:遍历完所有数后,堆中将包含最大的 10 个数。
- 时间复杂度:由于堆的操作是 O(log k),每次插入操作的时间复杂度为 O(log 10),因此整个过程的时间复杂度是 O(n log 10) ≈ O(n)。
5. 实现代码
5.1 完整代码
#include <stdio.h>
#include <stdlib.h>
// 最小堆的结构体定义
struct MinHeap {
int* arr; // 存储堆的数组
int size; // 当前堆的大小,即有数值的个数
int capacity; // 堆的最大容量
};
// 创建最小堆
struct MinHeap* createMinHeap(int capacity) {
// 定义一个MinHeap结构体大小的指针,指向一个堆
struct MinHeap* heap = (struct MinHeap*)malloc(sizeof(struct MinHeap));
heap->arr = (int*)malloc(sizeof(int) * capacity);
heap->size = 0;
heap->capacity = capacity;
return heap;
}
// 交换两个元素
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 维护堆的性质(向下调整)
void heapify(struct MinHeap* heap, int index) {
int left = 2 * index + 1;
int right = 2 * index + 2;
int smallest = index;
// 找出最小的元素
if (left < heap->size && heap->arr[left] < heap->arr[smallest]) {
smallest = left;
}
if (right < heap->size && heap->arr[right] < heap->arr[smallest]) {
smallest = right;
}
// 如果最小元素不是当前元素,交换并继续调整
if (smallest != index) {
swap(&heap->arr[index], &heap->arr[smallest]);
heapify(heap, smallest);
}
}
// 维护堆的性质(向上调整)
void upheapify(struct MinHeap* heap, int index) {
while (index > 0 && heap->arr[index] < heap->arr[(index - 1) / 2]) {
swap(&heap->arr[index], &heap->arr[(index - 1) / 2]);
index = (index - 1) / 2;
}
}
// 插入元素到堆中
void insert(struct MinHeap* heap, int value) {
if (heap->size < heap->capacity) {
// 如果堆未满,直接插入
heap->arr[heap->size] = value;
upheapify(heap, heap->size); // 插入后需要向上调整
heap->size++;
} else if (value > heap->arr[0]) {
// 如果堆已满且当前值大于堆顶元素,则替换堆顶
heap->arr[0] = value;
heapify(heap, 0); // 替换堆顶后需要进行堆化
}
}
// 打印堆中的前 10 个最大值
void printTop10(struct MinHeap* heap) {
// 最小堆中的前 10 个最大值已经存储在堆中,直接打印
for (int i = 0; i < heap->size; i++) {
printf("%d ", heap->arr[i]);
}
printf("\n");
}
// 主程序
int main() {
struct MinHeap* heap = createMinHeap(10); // 创建一个容量为 10 的最小堆
int value;
printf("请输入 80000 个整数(每输入一个整数后按 Enter,输入 80000 个数):\n");
// 读取 80,000 个整数
for (int i = 0; i < 80000; i++) {
scanf("%d", &value);
insert(heap, value); // 将输入的值插入堆中
}
// 打印堆中的前 10 个最大值
printf("最大的 10 个整数是:\n");
printTop10(heap);
// 释放堆内存
free(heap->arr);
free(heap);
return 0;
}
6. 代码说明
- 结构体定义:我们定义了一个
MinHeap
结构体来表示最小堆,包含一个数组arr
存储堆的元素,size
表示当前堆的大小,capacity
是堆的最大容量(即 10)。 - 堆的操作:
createMinHeap
:创建一个新的最小堆。swap
:交换堆中的两个元素。heapify
:维护堆的性质,确保堆仍然是最小堆。insert
:将新元素插入堆。如果堆未满,直接插入。如果堆已满并且新元素大于堆顶元素,则替换堆顶并重新调整堆。printTop10
:打印堆中的前 10 个最大值(即堆中的元素)。
- 主程序:
- 通过
scanf
读取 80,000 个整数,并将它们插入最小堆。 - 插入操作将保证堆中始终保存着最大的 10 个元素。
- 最后输出堆中的元素,即为最大的 10 个整数。
- 通过
7. 模拟过程
假设输入为:
2 5 8 12 20 10 1 35 27 50 41 39 70 80 90 23 17 16 13 11 ...
程序将使用最小堆的结构,维护堆中最大 10 个数。每读取一个新数,程序将插入最小堆,并保证堆的大小不超过 10。当所有 80,000 个数输入完成后,堆中将包含最大的 10 个数。
8. 运行结果
假设输入的数据中最大的 10 个数为:90, 80, 70, 50, 41, 39, 35, 27, 23, 20
,程序输出:
最大的 10 个整数是:90 80 70 50 41 39 35 27 23 20
注意,此代码只会获取最大的10个数,但不会排序这10个数。
9. 时间和空间复杂度分析
- 时间复杂度:
- 建堆的时间复杂度:每次插入一个元素时,最小堆的插入操作为 O(log 10) = O(1),因此整个过程的时间复杂度是 O(n),其中
n
为 80,000。
- 建堆的时间复杂度:每次插入一个元素时,最小堆的插入操作为 O(log 10) = O(1),因此整个过程的时间复杂度是 O(n),其中
- 空间复杂度:最小堆需要 O(10) 的空间来存储最大 10 个数,因此空间复杂度为 O(1),即常数空间。
10. 总结
通过使用最小堆,我们能够以 O(n) 的时间复杂度找到并输出最大的 10 个数。这种方法比直接排序更高效,尤其是当数据量很大时。
相关文章:
利用编程思维做题之最小堆选出最大的前10个整数
1. 理解问题 我们需要设计一个程序,读取 80,000 个无序的整数,并将它们存储在顺序表(数组)中。然后从这些整数中选出最大的前 10 个整数,并打印它们。要求我们使用时间复杂度最低的算法。 由于数据量很大,直…...

详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西:MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO 文章目录 1.架构1.1 基本…...
Unity C# 影响性能的坑点
c用的时间长了怕unity的坑忘了,记录一下。 GetComponent最好使用GetComponent<T>()的形式, 继承自Monobehaviour的函数要避免空的Awake()、Start()、Update()、FixedUpdate().这些空回调会造成性能浪费 GetComponent方法最好避免在Update当中使用…...

工作学习:切换git账号
概括 最近工作用的git账号下发下来了,需要切换一下使用的账号。因为是第一次弄,不熟悉,现在记录一下。 打开设置 路径–git—git remotes,我这里选择项是Manage Remotes,点进去就可以了。 之后会出现一个输入框&am…...
量化交易系统开发-实时行情自动化交易-8.量化交易服务平台(一)
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于收集整理的33个量化交易服…...

Scala习题
姓名,语文,数学,英语 张伟,87,92,88 李娜,90,85,95 王强,78,90,82 赵敏,92,88,91 孙涛,…...

结构方程模型(SEM)入门到精通:lavaan VS piecewiseSEM、全局估计/局域估计;潜变量分析、复合变量分析、贝叶斯SEM在生态学领域应用
目录 第一章 夯实基础 R/Rstudio简介及入门 第二章 结构方程模型(SEM)介绍 第三章 R语言SEM分析入门:lavaan VS piecewiseSEM 第四章 SEM全局估计(lavaan)在生态学领域高阶应用 第五章 SEM潜变量分析在生态学领域…...

OpenCV图像基础处理:通道分离与灰度转换
在计算机视觉处理中,理解图像的颜色通道和灰度表示是非常重要的基础知识。今天我们通过Python和OpenCV来探索图像的基本组成。 ## 1. 图像的基本组成 在数字图像处理中,彩色图像通常由三个基本颜色通道组成: - 蓝色(Blue&#x…...

C++ 类和对象(类型转换、static成员)
目录 一、前言 二、正文 1.隐式类型转换 1.1隐式类型转换的使用 2.static成员 2.1 static 成员的使用 2.1.1static修辞成员变量 2.1.2 static修辞成员函数 三、结语 一、前言 大家好,我们又见面了。昨天我们已经分享了初始化列表:https://blog.c…...

【网络安全设备系列】12、态势感知
0x00 定义: 态势感知(Situation Awareness,SA)能够检测出超过20大类的云上安全风险,包括DDoS攻击、暴力破解、Web攻击、后门木马、僵尸主机、异常行为、漏洞攻击、命令与控制等。利用大数据分析技术,态势感…...

Linux介绍与安装指南:从入门到精通
1. Linux简介 1.1 什么是Linux? Linux是一种基于Unix的操作系统,由Linus Torvalds于1991年首次发布。Linux的核心(Kernel)是开源的,允许任何人自由使用、修改和分发。Linux操作系统通常包括Linux内核、GNU工具集、图…...
BGE-M3模型结合Milvus向量数据库强强联合实现混合检索
在基于生成式人工智能的应用开发中,通过关键词或语义匹配的方式对用户提问意图进行识别是一个很重要的步骤,因为识别的精准与否会影响后续大语言模型能否检索出合适的内容作为推理的上下文信息(或选择合适的工具)以给出用户最符合…...

鸿蒙NEXT开发案例:文字转拼音
【引言】 在鸿蒙NEXT开发中,文字转拼音是一个常见的需求,本文将介绍如何利用鸿蒙系统和pinyin-pro库实现文字转拼音的功能。 【环境准备】 • 操作系统:Windows 10 • 开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.…...
CTF之密码学(栅栏加密)
栅栏密码是古典密码的一种,其原理是将一组要加密的明文划分为n个一组(n通常根据加密需求确定,且一般不会太大,以保证密码的复杂性和安全性),然后取每个组的第一个字符(有时也涉及取其他位置的字…...

修改插槽样式,el-input 插槽 append 的样式
需缩少插槽 append 的 宽度 方法1、使用内联样式直接修改,指定 width 为 30px <el-input v-model"props.applyBasicInfo.outerApplyId" :disabled"props.operateCommandType input-modify"><template #append><el-button click…...

UPLOAD LABS | PASS 01 - 绕过前端 JS 限制
关注这个靶场的其它相关笔记:UPLOAD LABS —— 靶场笔记合集-CSDN博客 0x01:过关流程 本关的目标是上传一个 WebShell 到目标服务器上,并成功访问: 我们直接尝试上传后缀为 .php 的一句话木马: 如上,靶场弹…...

【css实现收货地址下边的平行四边形彩色线条】
废话不多说,直接上代码: <div class"address-block" ><!-- 其他内容... --><div class"checked-ar"></div> </div> .address-block{height:120px;position: relative;overflow: hidden;width: 500p…...
缓存方案分享
不知道大家平常更新缓存是怎么做的,但是大部分时候都是更新数据的同时更新缓存,今天和同事一起聊到一个缓存方案的问题,感觉很有趣、非常精妙,记录一下。 基于此本文将介绍几种常见的缓存更新策略,包括简单的缓存覆盖…...
第四十篇 DDP模型并行
摘要 分布式数据并行(DDP)技术是深度学习领域中的一项重要技术,它通过将数据和计算任务分布在多个计算节点上,实现了大规模模型的并行训练。 DDP技术的基本原理是将数据和模型参数分割成多个部分,每个部分由一个计算节点负责处理。在训练过程中,每个节点独立计算梯度,…...

软件测试面试之常规问题
1.描述一下测试过程 类似题目:测试的生命周期 思路:这是一个“范围”很大的题目,而且回答时间一般在3分钟之内,不可能非常详细的描述整个过程,因此答题的思路要从整体结构入手,不要过细。为了保证答案的准确性,可以引…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...