数据结构 | 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
    • 然后再执行代码,可以看到已经完美的出来了~~
相关推荐
hn小菜鸡40 分钟前
LeetCode 377.组合总和IV
数据结构·算法·leetcode
Deepoch1 小时前
Deepoc 大模型:无人机行业的智能变革引擎
人工智能·科技·算法·ai·动态规划·无人机
heimeiyingwang9 天前
【深度学习加速探秘】Winograd 卷积算法:让计算效率 “飞” 起来
人工智能·深度学习·算法
时空自由民.9 天前
C++ 不同线程之间传值
开发语言·c++·算法
ai小鬼头9 天前
AIStarter开发者熊哥分享|低成本部署AI项目的实战经验
后端·算法·架构
小白菜3336669 天前
DAY 37 早停策略和模型权重的保存
人工智能·深度学习·算法
zeroporn9 天前
以玄幻小说方式打开深度学习词嵌入算法!! 使用Skip-gram来完成 Word2Vec 词嵌入(Embedding)
人工智能·深度学习·算法·自然语言处理·embedding·word2vec·skip-gram
亮亮爱刷题9 天前
飞往大厂梦之算法提升-7
数据结构·算法·leetcode·动态规划
_周游9 天前
【数据结构】_二叉树OJ第二弹(返回数组的遍历专题)
数据结构·算法
双叶8369 天前
(C语言)Map数组的实现(数据结构)(链表)(指针)
c语言·数据结构·c++·算法·链表·哈希算法