【算法篇】利用堆高效解决大数据量时TOP-K问题

news2024/9/22 17:30:13

Top-k问题

  • 1.问题描述
  • 2.分析问题
  • 3.思路
  • 4.复杂度分析
  • 5.代码实现
  • 6.总结

堆相关博客: 堆

1.问题描述

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

2.分析问题

最简单的方法就是排序,先排好序再取前k个数。
或者建立一个堆,存放所有的数据元素,依次弹出堆顶元素即可
但是这两种方法在数据量非常大时是不可取的
如果我们要排的是一个文件中的数据,如果数据非常多的话,可能数据都不能一下子加载到内存当中,所以我们要换一种思路,能不能每次让加载到内存中的数据量少一点,但又不影响我们的最终的要求。

3.思路

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

我们要求前k个最大元素,就建小堆。
原因是:一开始把数据中前k个数放进了我们建的堆,我们把它建成小堆的话,最顶部的元素一定是这个堆里面最小的数,然后依次拿N-K个元素与堆顶比较比堆顶元素大的数就进来,然后因为我们是小堆,所以这个数会向下调整原来堆中第二小的数到顶部,然后继续拿数据与堆顶比较,满足条件就进来,进来后就调整,这样一直下去直到结束,就是前数据中前k个最大的元素。

要求前k个最小的元素,则建大堆,与上同理。

4.复杂度分析

1.时间复杂度 O(N * log2K)

首先是选K个数放进堆,然后最坏情况下是每次都调整,就是(N-K)*log2K
K + (N - K) * log2K可以近似成 N * log2K

2.空间复杂度O(K)

5.代码实现

我们的data.txt文件数据是
在这里插入图片描述
在这里我们给的数据量很小来测试。

#include <stdio.h>
void swap(int* n1, int* n2)
{
	int tmp = *n1;
	*n1 = *n2;
	*n2 = tmp;
}
void down(data_type* a, int len, int parent) //向下调整
{
	int child = (parent * 2) + 1; // 先假设左孩子最大
	while (child < len)
	{
		//这里加1可能会有越界问题,可能会访问到随机值,导致出错,判断一下
		if (child + 1 < len && a[child + 1] < a[child]) // 如果右孩子大的话就 child++
		{
			child++;
		}
		if (a[parent] > a[child])//建立小根堆
		{
			swap(&a[parent], &a[child]);
			parent = child;
			child = (parent * 2) + 1;
		}
		else
		{
			break;
		}
	}
}
void test1()
{
	int minHeap[5];//建立一个堆,大小为5
	FILE* fout = fopen("data.txt", "r");//文件操作
	if (fout == NULL)//养成好习惯判断是否打开文件成功
	{
		perror("fopen");
		return;
	}
	int k = 5;//这里我们假设要求前5大的数
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minHeap[i]);//先往堆里读入前K个数
	}
	for (int i = (k - 1 - 1) / 2; i >= 0; i--)//建堆算法,不了解的可以看看文章开头提到的博客
	{
		down(minHeap, k, i);//
	}
	int val = 0;
	while (fscanf(fout, "%d", &val) != EOF)//继续读入N-K个数据,满足条件就进堆,进堆后进行调整。
	{
		if (val > minHeap[0])
		{
			minHeap[0] = val;
			down(minHeap, k, 0);
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", minHeap[i]);//打印前5大的数
		//77 777 999 9999 10000
	}
	fclose(fout);//养成好习惯fclose()
}
int main()
{
	test1();
	return 0;
}

6.总结

这里的优化避免我们需要排序文件中的数据时,文件中的数据量如果过大,一下子不能加载进来的情况(因为文件在磁盘,而我们的数组元素在内存。比如文件中有100亿个整数,内存大小就是40G,非常大),所以我们一个一个读入,避免了这种情况的发生。

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

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

相关文章

C语言第十九课:补充知识——函数栈帧的创建与销毁

目录 前言&#xff1a; 一、寄存器&#xff1a; 二、函数栈帧的创建与销毁&#xff1a; 1.main函数函数栈帧开辟的准备&#xff1a; 2.main函数函数栈帧的开辟&#xff1a; 3.Add函数函数栈帧的开辟&#xff1a; 4.Add函数函数栈帧的销毁&#xff1a; 5.main函数函数栈帧的销…

Linux多线程

Linux多线程 文章目录Linux多线程1.Linux线程概念1.1 什么是线程1.2 线程的执行流1.3 线程的优缺点1.4 线程的异常与用途2.进程与线程的区别总结3.多进程与多线程的应用场景4.线程控制4.1 进程ID与线程ID4.2 线程创建(pthread_create)4.3 线程终止(pthread_exit、pthread_cance…

Unity计算着色器 01

序 计算着色器&#xff0c;是什么&#xff1f; Unity中ComputeShader的基础介绍与使用 - 知乎 (zhihu.com) 好像是并行计算的一个东西。再具体的&#xff0c;看不懂了。 并行计算&#xff0c;显卡&#xff1f; 那看来得先了解显卡&#xff0c;铺垫一下&#xff0c;再计划…

算法前缀和

一 和为 k 的子数组 1.1 题目描述 给定一个整数数组和一个整数 k &#xff0c;请找到该数组中和为 k 的连续子数组的个数。 示例 1&#xff1a; 输入:nums [1,1,1], k 2 输出: 2 解释: 此题 [1,1] 与 [1,1] 为两种不同的情况 示例 2&#xff1a; 输入:nums [1,2,3], k…

由浅入深,详解 LiveData 的那些事

引言 关于LiveData,在2022尾声的今天&#xff0c;从事 Android 开发的小伙伴一定不会陌生。相应的&#xff0c;关于 LiveData 解析与使用的文章更是数不胜数&#xff0c;其中不乏优秀的创作者&#xff0c;在众多的文章以及前辈面前&#xff0c;本篇也不敢妄谈能写的多么深入,易…

python使用Flask,Redis和Celery的异步任务

介绍 随着Web应用程序的发展和使用的增加&#xff0c;用例也变得多样化。我们现在正在建设和使用网站来执行比以往任何时候都更复杂的任务。其中一些任务可以进行处理&#xff0c;并将反馈立即转发给用户&#xff0c;而其他任务则需要稍后进行进一步处理和结果转发。越来越多地…

冯诺依曼体系各硬件工作原理解析

文章目录计算机结构体系来源冯诺依曼体系结构主存储器的基本组成运算器的基本组成控制器的基本组成计算机的工作过程总结计算机结构体系来源 1946年,美国发明了世界上第一台计算机ENIAC,可用于比较快速的数据计算,但是其运算速度却受到了人工数据的输入速度的限制,为此我们现在…

NNDL实验 优化算法3D轨迹 鱼书例题3D版

这张图在网络上很流行。代码源自&#xff1a; 深度学习入门&#xff1a;基于Python的理论与实现 (ituring.com.cn) 2D版讲解&#xff1a;NNDL 作业11&#xff1a;优化算法比较 调整学习率等超参数&#xff0c;观察动画&#xff0c;可以加深对各种算法的理解。 配合实验的模型…

南方农业杂志南方农业杂志社南方农业编辑部2022年第19期目录

遗传育种 峨眉黑鸡遗传多样性及群体遗传结构分析 袁霞;刘方庆;文陇英;徐婧;廖光祥;王强胜;王湘; 1-7 栽培与植保《南方农业》投稿&#xff1a;cn7kantougao163.com 井窖式移栽烤烟前期地上部和地下部生长规律拟合分析 温明霞;郭发文;冯小芽;王军;刘京;彭剑涛;廉云; 8-1…

从进程的角度来看JVM的内存分布

JVM(下面JVM都是指代HotSpot)本质上是运行在操作系统上的一个C程序&#xff0c;本文会从这个角度来构建对于JVM内存的完整视角&#xff0c;以HotSpot这个JVM实现运行在Linux操作系统上进行分析&#xff0c;在分析的过程中会解释清楚一些不太好理解的概念&#xff0c;诸如堆外内…

双十二哪些数码好物值得入手?盘点双十二最值得入手的数码好物

双十二快到了&#xff0c;相信很多人像我一样想趁着年末入手数码产品&#xff0c;但又不知道什么值得入手。最近也听到很多人问&#xff0c;针对这个问题&#xff0c;我来给大家盘点双十二最值得入手的数码好物&#xff0c;有需要的可以当个参考。 一、南卡小音舱蓝牙耳机 推…

怎样批量查询网站是否被搜狗收录?批量查询网站搜狗收录的详细教程

怎样批量查询网站是否被搜狗收录&#xff1f;批量查询网站搜狗收录的详细教程 批量查询网站搜狗收录的的具体操作&#xff1a; 第一步、打开站长工具 第二步、添加需要查询的网站域名 第三步、勾选要查询的功能&#xff08;勾选搜狗是否收录和搜狗总收录) 第四步、提交查询 第…

手把手教你在Ubuntu22.04 上安装 Vivado、HLS、Vitis 2022.2版本

文章目录1 Vivado22.2 和 HLS 22.2 安装下载安装包执行.bin文件开始安装命令配置启动问题2 Vitis 22.2 安装3 卸载Xilinx我是 雪天鱼&#xff0c;一名FPGA爱好者&#xff0c;研究方向是FPGA架构探索和数字IC设计。欢迎来关注我的B站账号&#xff0c;我将定期更新IC设计教程。 …

手撕红黑树 | 变色+旋转你真的明白了吗?【超用心超详细图文解释 | 一篇学会Red_Black_Tree】

说在前面 我们也很久没有更新数据结构系列了&#xff0c;半年前博主重新深入学习了红黑树这个数据结构&#xff0c;一直想更新呈现给大家&#xff0c;最近也一直没有时间&#xff0c;今天红黑树它来了&#xff01; 博主为了这篇博客&#xff0c;做了很多准备&#xff0c;试了…

怎么修复老照片?给你推荐这几个修复方法

相信大家的家里都有老照片吧&#xff0c;那在你们翻看这些老照片的时候&#xff0c;有没有发现有些老照片变得有些破旧、泛黄、模糊等情况呢&#xff1f;看到这些情况&#xff0c;大家是不是会很心疼呢&#xff1f;因为这些老照片都充满了各种各样的回忆&#xff0c;根本拍不出…

Docker查看容器的初始启动命令参数的常见几种方式

1.在使用docker容器的过程中&#xff0c;经常需要查看容器启动的命令来看当时启动容器时候所用的参数&#xff0c;如果时间不是很久或者通过history命令就可以很容易的想起或查看到命令&#xff0c;一旦时间过了很久或history被清空那么就无法获取命令&#xff0c;如下所示dock…

cengbox2靶机(hydra爆破、公私钥免密登录)

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;zdpr 虚拟机网络链接模式&#xff1a;桥接模式 攻击机系统&#xff1a;kali linux 2021.1 信息收集 1.arp-scan -l探测目标靶机ip 2.nmap -p- -A -T4 192.168.1.107 探测目标靶机开放端口和服务 …

Docker基本使用

1、centos7安装docker engine 参考文档&#xff1a;https://docs.docker.com/engine/install/centos/ &#xff08;1&#xff09;卸载之前的docker sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \…

Spring——AOP

Spring中的可插拔组件技术 Spring AOP Spring AOP——Aspect Oriented Programming 面向切面编程AOP 的做法是将通用的、与业务无关的功能抽象封装为切面层切面可配置在目标方法执行前后&#xff0c;做到即插即用 不修改源码对程序功能进行拓展 AoP的关键概念 Spring AoP 与A…

栈与队列3:有效的括号

主要是我自己刷题的一些记录过程。如果有错可以指出哦&#xff0c;大家一起进步。 转载代码随想录 原文链接&#xff1a; 代码随想录 leetcode链接&#xff1a;20. 有效的括号 题目&#xff1a; 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&am…