解析Top-K问题及堆排序算法

Top-K问题是在海量数据中找到最大或最小的K个元素,它在实际应用中非常常见,例如专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。在面对大规模数据时,直接对数据进行排序可能效率低下,因为排序的时间复杂度通常为O(n log n),而海量数据可能无法完全加载到内存中。因此,我们需要一种更高效的算法来解决Top-K问题

 

用堆解决Top-K问题

堆排序是一种高效的解决Top-K问题的方法。基本思路如下:

  1. 用数据集合中前K个元素来建堆。对于前K个最大的元素,我们建立一个小堆;对于前K个最小的元素,我们建立一个大堆。

  2. 用剩余的N-K个元素依次与堆顶元素来比较,如果大于(或小于)堆顶元素,则替换堆顶元素,并进行堆调整。

通过这个过程,堆中剩余的K个元素就是所求的前K个最小或最大的元素

void PrintTopK(int* a, int n, int k)
{// 1. 建堆--用a中前k个元素建堆// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换
}
void TestTopk()
{int n = 10000;int* a = (int*)malloc(sizeof(int)*n);srand(time(0));for (size_t i = 0; i < n; ++i){a[i] = rand() % 1000000;}a[5] = 1000000 + 1;a[1231] = 1000000 + 2;a[531] = 1000000 + 3;a[5121] = 1000000 + 4;a[115] = 1000000 + 5;a[2335] = 1000000 + 6;a[9999] = 1000000 + 7;a[76] = 1000000 + 8;a[423] = 1000000 + 9;a[3144] = 1000000 + 10;PrintTopK(a, n, 10);
}

对随机位置改10个值  如果能选出这10个 就说明代码没问题

假设有10亿个值  这时让你取前10 那我们选择建立一个10个数据大小的堆

我们读写整形用fscanf   和fprintf

这时我们创建一个函数将其写入文档

void CreateNode()
{int n = 10000000;srand(time(0));const char* file = "data.txt";FILE* fin= fopen(file, "w");if (fin == NULL){perror("fopen fail");return;}for (int i = 0; i < n; ++i){int x = (rand() + i) % 10000000;//+i是为了减少重复值 因为rand最多就三万个随机值 fprintf(fin, "%d\n", x);}
}

 

此时文件已经被创建成功 

 

接下来实现打印Top k

 在这里我们创建了一个小堆 由于fscanf的返回值是当读取结束时返回EOF

 所以我们可以创造循环

 然后我们填写测试用例

通过调试我们可以看到他的逻辑过程 

 最后得出结果

实现代码

以下是一个简单的C语言代码示例,展示了如何使用小堆解决Top-K问题:

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>// 堆数据结构
typedef struct {int* a;         // 存放堆元素的数组int capacity;   // 数组容量int size;       // 当前堆的大小
} HP;// 交换两个元素的值
void Swap(int* p1, int* p2) {int tmp = *p1;*p1 = *p2;*p2 = tmp;
}// 向上调整(建堆时使用)
void Adjustup(int* a, int child) {int parent = (child - 1) / 2;while (child > 0 && a[child] < a[parent]) {Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}
}// 向下调整(堆调整时使用)
void Adjustdown(int* a, int size, int parent) {int child = parent * 2 + 1;while (child < size) {if (child + 1 < size && a[child + 1] < a[child]) {++child;}if (a[child] < a[parent]) {Swap(&a[child], &a[parent]);parent = child;child = (child + 1) * 2;} else {break;}}
}// 初始化堆
void HPInit(HP* php, int capacity) {php->a = (int*)malloc(sizeof(int) * capacity);php->capacity = capacity;php->size = 0;
}// 销毁堆
void HPDestory(HP* php) {free(php->a);php->a = NULL;php->capacity = 0;php->size = 0;
}// 入堆操作
void HPPush(HP* php, int x) {if (php->size == php->capacity) {// 堆满时,扩容int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;int* tmp = (int*)realloc(php->a, sizeof(int) * newcapacity);if (tmp == NULL) {perror("realloc fail");return;}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;Adjustup(php->a, php->size - 1);
}// 出堆操作
int HPPop(HP* php) {if (php->size == 0) {perror("Heap is empty");return -1;  // 堆为空}int top = php->a[0];php->a[0] = php->a[php->size - 1];php->size--;Adjustdown(php->a, php->size, 0);return top;
}// 获取堆顶元素
int HPTop(const HP* php) {if (php->size == 0) {perror("Heap is empty");return -1;  // 堆为空}return php->a[0];
}// 打印前K个最小元素
void PrintTopK(const char* file, int k) {FILE* fin = fopen(file, "r");if (fin == NULL) {perror("fopen fail");return;}// 建立一个大小为k的小堆HP minheap;HPInit(&minheap, k);int x = 0;// 读取文件中的元素并插入堆while (fscanf(fin, "%d", &x) != EOF) {if (minheap.size < k) {// 如果堆的大小小于k,直接插入HPPush(&minheap, x);} else if (x > HPTop(&minheap)) {// 否则,如果当前元素比堆顶元素大,替换堆顶元素并调整堆HPPop(&minheap);HPPush(&minheap, x);}}// 输出结果for (int i = 0; i < k; i++) {printf("%d ", HPPop(&minheap));}printf("\n");fclose(fin);HPDestory(&minheap);
}// 生成随机数据文件
void CreateNode() {int n = 10000000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL) {perror("fopen fail");return;}for (int i = 0; i < n; ++i) {int x = (rand() + i) % 10000000;fprintf(fin, "%d\n", x);}fclose

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

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

相关文章

lxd提权

lxd/lxc提权 漏洞介绍 lxd是一个root进程&#xff0c;它可以负责执行任意用户的lxd&#xff0c;unix套接字写入访问操作。而且在一些情况下&#xff0c;lxd不会调用它的用户权限进行检查和匹配 原理可以理解为用用户创建一个容器&#xff0c;再用容器挂载宿主机磁盘&#xf…

ZooKeeper的分布式锁---客户端命令行测试(实操课程)

本系列是zookeeper相关的实操课程&#xff0c;课程测试环环相扣&#xff0c;请按照顺序阅读测试来学习zookeeper。阅读本文之前&#xff0c;请先阅读----​​​​​​zookeeper 单机伪集群搭建简单记录&#xff08;实操课程系列&#xff09;。 阅读本文之前&#xff0c;请先阅读…

在macOS上使用Homebrew安装PHP的完整指南

安装最新版本的PHP 步骤1: 安装Homebrew 在安装最新版本的PHP之前&#xff0c;确保你的macOS系统上已经安装了Homebrew。如果尚未安装&#xff0c;打开终端并运行以下命令&#xff1a; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install…

线性表——(2)线性表的顺序存储及其运算的实现

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 看到美好&#xff0c;感受美好&a…

GDPU 数据结构 天码行空12

文章目录 数据结构实验十二 图的遍历及应用一、【实验目的】二、【实验内容】三、实验源代码&#x1f37b; CPP&#x1f37b; C 数据结构实验十二 图的遍历及应用 一、【实验目的】 1、 理解图的存储结构与基本操作&#xff1b; 2、熟悉图的深度度优先遍历和广度优先遍历算法…

WEB渗透—反序列化(九)

Web渗透—反序列化 课程学习分享&#xff08;课程非本人制作&#xff0c;仅提供学习分享&#xff09; 靶场下载地址&#xff1a;GitHub - mcc0624/php_ser_Class: php反序列化靶场课程&#xff0c;基于课程制作的靶场 课程地址&#xff1a;PHP反序列化漏洞学习_哔哩哔_…

centos7内核升级(k8s基础篇)

1.查看系统内核版本信息 uname -r 2.升级内核 2.1更新yum源仓库 yum -y update更新完成后&#xff0c;启用 ELRepo 仓库并安装ELRepo仓库的yum源 ELRepo 仓库是基于社区的用于企业级 Linux 仓库&#xff0c;提供对 RedHat Enterprise (RHEL) 和 其他基于 RHEL的 Linux 发行…

Vue.set的实现原理

给对象和数组本身都增加了dep属性当给对象新增不存在的属性则触发对象依赖的watcher去更新当修改数组索引时&#xff0c;我们调用数组本身的splice去更新数组&#xff08;数组的响应式原理就是重新了splice等方法&#xff0c;调用splice就会触发视图更新&#xff09; 以下方法调…

mysql的外键

MySQL 中的外键是一种关系型数据库特性&#xff0c;用于在两个表之间建立关联。外键定义了一个表中的列&#xff08;或多列&#xff09;与另一个表中的数据的关系&#xff0c;通常是通过主键和外键之间的关联。在 Django 的模型中&#xff0c;外键通过 models.ForeignKey 字段来…

企业计算机服务器中了mallox勒索病毒如何解密,mallox勒索病毒文件恢复

随着网络技术的不断发展&#xff0c;网络安全威胁也在不断增加&#xff0c;勒索病毒攻击企业计算机服务器的事件时有发生&#xff0c;并且勒索病毒的加密形式也越来越复杂。近期&#xff0c;云天数据恢复中心陆续接到很多企业的求助&#xff0c;企业的计算机服务器遭到了mallox…

单片机----串行通信

目录 串行通信的两种方式 串行通信的传输模式 串行通信的错误校验 1.奇偶校验 2.代码和校验 3.循环冗余码校验 串行口结构 串行口控制寄存器SCON 特殊功能寄存器PCON 串行口的4种工作方式 方式0&#xff1a; &#xff08;1&#xff09;方式0的发送过程 &#xff0…

QString

目录 1 toInt() &#xff08;1&#xff09;qt_strtoll() &#xff08;2&#xff09; qstrtoll() &#xff08;3&#xff09;bytearrayToLongLong&#xff08;&#xff09; &#xff08;4&#xff09;toIntegral_helper 1 toInt() 下面是toInt()函数的内部实现源码 QStri…

如何使用阿里云虚拟主机和域名设置网站?

本文档将向您展示如何使用阿里云虚拟主机来设置一个新网站&#xff0c;并完成一个域名。如果您按照此处的步骤操作&#xff0c;您将启动并运行一个新网站&#xff0c;可以使用您选择的名称在全球范围内访问&#xff0c;并托管在阿里云平台上。 本文档假设您已经拥有有效的阿里…

InstructDiffusion-多种视觉任务统一框架

论文:《InstructDiffusion: A Generalist Modeling Interface for Vision Tasks》 github&#xff1a;https://github.com/cientgu/InstructDiffusion InstructPix2Pix&#xff1a;参考 文章目录 摘要引言算法视觉任务统一引导训练集重构统一框架 实验训练集关键点检测分割图像…

微信小程序本地和真机调试文件上传成功但体验版不成功

可能是微信小程序ip白名单的问题&#xff0c;去微信公众平台&#xff08;小程序&#xff09;上设置小程序的ip白名单 1、在本地中取消不校验 然后在本地去上传文件&#xff0c;就会发现控制台报错了&#xff0c;会提示一个https什么不在ip白名单&#xff0c;复制那个网址 2、…

tomcat调优配置

一. 设置账户进入管理页面 通过浏览器进入Tomcat7的管理模块页面&#xff1a;http://localhost:8080/manager/status 按照提示&#xff0c;在Tomcat7服务器指定的位置修改配置文件&#xff08;conf/tomcat-users.xml&#xff09;&#xff0c;增加相应的用户和角色配置标签 <…

win11系列:避坑宝典|win11升级最新预览体验版bug梳理

win11系列&#xff1a;避坑宝典|win11升级最新预览体验版bug梳理 一、亲测win11升级的前世今生。&#xff08;一&#xff09;问题描述梳理。&#xff08;二&#xff09;故障原因分析。&#xff08;三&#xff09;具体解决方案。2.【已解决】①尝试关Hyper-v重启&#xff1b;②从…

基于AOP的声明式事物控制

目录 Spring事务编程概述 基于xml声明式事务控制 事务属性 isolation timeout read-only propagation 全注解开发 Spring事务编程概述 事务是开发中必不可少的东西&#xff0c;使用JDBC开发时&#xff0c;我们使用connection对事务进行控制&#xff0c;使用MyBatis时&a…

Django大回顾 -3 之响应对象、cbv和fbv、关于类中self是谁的问题、上传文件、模版

【1】isinstance方法 判断一个对象是否是一个已知的类型。 isinstance语法&#xff1a; isinstance(object&#xff0c;classinfo) object --------- 实例化对象 cassinfo ------- 可以是字节或间接类名、基本类型&#xff0c;或者由他们组成的元组 相同返回True&#xff0c;不…

肖sir__mysql之视图__009

mysql之视图 一、什么是视图 视图是一个虚拟表&#xff08;逻辑表&#xff09;&#xff0c;它不在数据库中以存储形式保存&#xff08;本身包含数据&#xff09;&#xff0c;是在使用视图的时候动态生成。 二、视图作用 1、查询数据库中的非常复的数据 例如&#xff1a;多表&a…