Topk问题——求n个数据中前n个最大或最小元素

什么是Topk问题?

Topk问题就是求数据中前k个最大或者最小元素,一般情况下,使用Topk来解决的问题,所面对的数据量都很大。同时Topk可以在空间和时间上都有很好的效率。

解决思路:

①正常情况下,我们求N个数据中前k个最大或最小元素,我们首先要排序数据,然后依次读出前k个最大或最小元素。

但是,如果面对海量的数据,先不说对这些数据排序的消耗有多大;单是能否读取到内存都是问题,所以要处理海量的数据,排序再打印行不通。

②使用建堆+比较的方法

首先,建立k个元素总大小的空间;

其二,将前k个元素存储到这个空间;

其三,将这k个元素建堆,求前k个最大元素——建小堆,求前k个最小元素——建大堆;

其四,将后面k~N个元素依次和堆顶元素比较,如果是大堆情况下,有元素大于堆顶元素,则令该元素覆盖堆顶元素。然后向下调整重新成堆。循环,直到数据随后一个元素。

最后堆中的元素就是这些数据中最大/最小的元素。

代码实现:

①向下调整函数:
void AdjustDown(HeapType* a, int size, int parent)
{
	assert(a);//判断传过来的指针是否为空
	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;
		}
	}
}
②创建数据,为后面求Topk准备
void CreateData()
{
	int n = 1000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen fail");
		return;
	}
	int i = 0;
	for (i = 0; i < n; i++)
	{
		int a = rand() % 10000;
		fprintf(fin, "%d\n", a);
	}
	fclose(fin);
}
③打印数据中前k个最大/最小值(这边以求前k个最大值演示)
void PrintTopk(int k)
{
	const char* file = "data.txt";
	FILE* fout = fopen(fout, "r");//创建文件指针指向前面创建的存储数据的文件
	if (fout == NULL)//判断是否创建成功
	{
		perror("fopen fail");
		return;
	}

	int* kminheap = (int*)malloc(sizeof(int) * k);//开辟k个元素大小的空间
	if (kminheap == NULL)
	{
		perror("malloc fail");
		return;
	}

	int i = 0;
	for (i = 0; i < k; i++)//在k个空间中存储好前k个数据
	{
		fscanf(fout, "%d", &kminheap[i]);
	}

	for (i = (k - 1 - 1) / 2; i >= 0; i--)//将存储好的数据向下调整建堆
	{
		AdjustDown(kminheap, k, i);
	}

	int val = 0;
	while (feof(fout))//循环比较剩余数据,更新堆中的元素,使得堆中元素为当前最大
	{
		fscanf(fout, "%d", &val);
		if (kminheap[0] < val)
		{
			kminheap[0] = val;
			AdjustDown(kminheap, k, 0);
		}
	}

	for (i = 0; i < k; i++)//打印出堆中所有元素,这些元素为数据中最大的k个元素
	{
		printf("%d  ", kminheap[i]);
	}
	free(kminheap);
	kminheap = NULL;
	fclose(fout);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

S+叮当猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值