TOPK问题的求解

在这片文章详解二叉树-CSDN博客中我们提到,如果要在非常多的数据(内存存不下)中找到最大或最小的前K个数,我们需要先构建一个K个数的小堆或大堆;再跟堆顶数据比较

要找最大的前K个数建小堆;要找最小的前K个数建大堆

1.构造数据

既然数据在内存中存不下,我们就放到文件中;需要构造一个有很多数据的文件

  • 我们以“w”的方式打开一个文件,如果该文件不存在,则会先创建该文件
  • 假设文件需要100万个数据;使用rand函数随机取数,用fprintf写文件TOPK问题的求解_第1张图片
//构造数据
void CreateData()
{
	srand(time(0));

	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("CreateData:create data fail");
		exit(-1);
	}

	int n = 1000000;
	for (int i = 0; i < n; i++)
	{
		int x = rand() % 1000000 + i;
		fprintf(pf, "%d\n", x);
	}

	fclose(pf);
	pf = NULL;
}

2.建堆

我们就拿取最大的前K个数来示范了,取最小的前K个数只要将建小堆改成建大堆即可

  • 首先向文件读取k个数据,放到创建好的数组中
  • 利用向下调整算法,将这k个数建成小堆
	//建小堆
	int* minHeap = (int*)malloc(sizeof(int) * k);
	if (minHeap == NULL)
	{
		perror("PrintTOPK:malloc fail");
		exit(-1);
	}

	for (int i = 0; i < k; i++)
	{
		fscanf(pf, "%d", &minHeap[i]);
	}
	
	for (int i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(minHeap, k, i);
	}

3.与堆顶数据比较

  • 利用fscanf的返回值来判断文件是否结束
  • 将读取到的数据与堆顶数据比较,如果比堆顶数据大,则交换,再对堆顶数据执行一次向下调整
	//堆顶数据与文件后面数据比较
	int x = 0;
	while (fscanf(pf, "%d", &x) != EOF)
	{
		if (x > minHeap[0])
		{
			minHeap[0] = x;
			AdjustDown(minHeap, k, 0);
		}
	}

4.复杂度计算

空间复杂度:O(K)

时间复杂度:O(N*\log_{2}{K} )


源码:TOPK/TOPK · baiyahua/LeetCode - 码云 - 开源中国 (gitee.com)

你可能感兴趣的:(数据结构,数据结构)