数据结构 | TOP-K问题

数据结构 | TOP-K问题

文章目录

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

就是从N个数里面找最大前K个(N远大于K)


思路一:

  • N个数插入到堆里面,PopK次

时间复杂度是O(N*logN) + K*logN == O(N*logN)

  • N很大很大,假设N是100亿,K是10
    100亿个整数大概需要40G左右

所以这个思路很不好~~


思路二:

  • 读取前K个值,建立K个数的小堆
    依次再取后面的值,跟堆顶比较,如果比堆顶大,替换堆顶进堆(替换对顶值,再向下调整)

时间复杂度是O(N*logK)

随机生成一些数据,找前k个最大值

  • 那么我们就先要造数据,随机生成
c 复制代码
void CreateData()
{
	//造数据
	int n = 100000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % 100000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}
  • 打开项目的源文件所在的文件夹,就会有这个data.txt的文件,里面已经随机生成了10万个数字

进行取前k个值建堆

  • 我们先从文件中读数据
  • 然后取前k个进行建立一个小堆
  • 读取前k个数,边读边建立小堆
  • 如果读取的整数 x 大于堆顶元素,将堆顶元素替换为 x,然后进行向下调整
c 复制代码
void PrintTopK(const char* file, int k)
{
	//读文件
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	//建立一个k个数的小堆
	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc error");
		return;
	}

	//读取前k个数
	//边读边建小堆
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
		AdjustUp(minheap, i);
	}
	
	//读取剩余的值,读到x里
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > minheap[0])
		{
			minheap[0] = x;
			//向下调整
			AdjustDown(minheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", minheap[i]);
	}
	
	free(minheap);
	fclose(fout);
}

找到了前k个结果以及全部代码

  • 比如我取前5个最大的,我们来看一下结果
c 复制代码
void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);

			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
void AdjustDown(HPDataType* 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 = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void CreateData()
{
	//造数据
	int n = 100000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}
	for (int i = 0; i < n; i++)
	{
		int x = (rand() + i) % 100000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}


void PrintTopK(const char* file, int k)
{
	//读文件
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	//建立一个k个数的小堆

	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc error");
		return;
	}

	//读取前k个数
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
		//向上调整
		AdjustUp(minheap, i);
	}

	//边读边建小堆
	//读取剩余的值,读到x里
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		//如果堆里的元素小于x就继续调整
		if (minheap[0] < x)
		{
			//将x搞到堆顶
			minheap[0] = x;
			//向下调整
			AdjustDown(minheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", minheap[i]);
	}

	free(minheap);
	fclose(fout);
}

int main()
{
	//CreateData();
	PrintTopK("data.txt",5);

	return 0;
}
  • 那么我们知道这前5个是最大的吗?

  • 这个时候就要加入我们的密探,手动从文件里加入5个最大的数~~

    • 加入这几个数100001 100002 100003 100005 100004
    • 然后再执行代码,可以看到已经完美的出来了~~
相关推荐
jyyyx的算法博客7 分钟前
传球游戏【思维】
算法
FL162386312915 分钟前
关于2026年南昌大学811信号与系统最后一题电路系统解题思路
算法
殷色玫瑰16 分钟前
C++ STL:map 与 set 详解——从底层红黑树到实际应用
c语言·数据结构·c++·算法·visualstudio·rpc
行者全栈架构师22 分钟前
【鸿蒙心迹】鸿蒙网络请求架构实战——@ohos.net.http 到 Axios 封装、拦截器与统一错误处理(HarmonyOS 7.x)
前端·算法·架构
小宋102136 分钟前
OpenTelemetry GenAI可观测性实战:串起模型、工具、Token与错误
java·人工智能·算法·贪心算法
嫂子开门我是_我哥38 分钟前
青少年抑郁、焦虑、失眠与自杀相关表现的症状联系:一篇网络分析论文所使用的算法深度解读
论文阅读·算法·论文笔记
字节跳动的猫1 小时前
LikeShop 商品评价体系二开:追评、晒图审核与评价标签筛选功能开发
运维·数据结构·数据库
渊鱼L1 小时前
CAD随机颗粒插件2D V2.0 更新说明
算法
Lazionr1 小时前
unordered_map和unordered_set的使用
开发语言·c++·算法
行者全栈架构师1 小时前
从 55% 到 6%:一个快餐营养规划器的算法迭代实录
后端·算法·架构