堆排序--TOP-K问题(详细讲解)

目录

一、TOP-K问题

1.思路1:使用排序,插入后pop?

思路2:时间复杂度O(N*logK)

二、 实现

1. 创造一个大文件用于存放数据

2. 根据思路我们写出代码

3.如何检验我所写的代码正确,根据最后生成的数据就可以看出吗?

三、程序实现完整代码


一、TOP-K问题

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

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家、全中国最好吃的火锅店前十等。

1.思路1:使用排序,插入后pop?

对于Top-K问题,能想到的最简单直接的方式就是排序。

但是:如果数据量非常大,排序就不太可取了。(可能数据都不能一下子全部加载到内存中)

N个数里面找最大前K个 (N远大于K)
思路1:
N个数插入到大堆里面,PopK次
时间复杂度:
N*LogN + K*logN -> O(N*IogN)
N很大很大,假设N是100亿,K是10
100亿个整数需要多少空间?
1G=1024MB=1024*1024KB=1024*1024*1024Byte 约等于10亿Byte
40G左右

思路2:时间复杂度O(N*logK)

1. 读取前K个值,建立K个数的一个小堆

2. 依次再读取后面的值,跟堆顶比较。如果谁比堆顶大,替换谁进堆(替换堆顶的值,在向下调整)

注意:此时,堆顶是第十大的数。我们每一次让新的数进堆,都是在替换掉,已经建好的堆里数最小的数。

二、 实现

1. 创造一个大文件用于存放数据

void CreateNDate()

{
   int n= 10000;
   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;/
/产生一个随机数,让所有值在100000以内,库里的随机                                                     // 最多只能产生30000多个,因此不能写成int x = (rand())%100000
    fprintf(fin,"%d\n",x);//将值输入到文件中
}
    fclose(fin);
}

2. 根据思路我们写出代码

void PrintTopK(const char* file,int k)

{
    FILE* fp = fopen(file, "r");

    if (fp == NULL)
    {
        perror("fopen fail!");
        return;
    }

    //根据要取的个数k,创建一个小堆并包含k个数
    //以数组的方式存放

    int* aheap = (int*)malloc(sizeof(int) * k);
    if (aheap == NULL)
    {
        perror("malloc fail!");
    }

    //从文件中读取前k个
    for (int i = 0; i < k; i++)
    {
        fscanf(fp, "%d", &aheap[i]);
        AdjustUp(aheap, i);

    }

    int x = 0;
    while (fscanf(fp, "%d", &x )!=EOF)
    {
        if (x > aheap[0])
//当从文件里取出这个数大于堆顶就进堆
        {
            aheap[0] = x;
            Adjustdown(aheap, k, 0);
//然后向下调整
        }
    }
    for (int i = 0; i < k; i++)
    {
        printf("%d ", aheap[i]);
    }
    printf("\n");
    free(aheap);
    fclose(fp);
}

注意:在创建文件写入数据时,加空格或者换行,都是为了,读取时能直接读取对应的数据。

3.如何检验我所写的代码正确,根据最后生成的数据就可以看出吗?

如图:

注意:在写入新数据,保存文件之后,在主函数中需要将调用CreateNDate()的函数注释。

三、程序实现完整代码

#include"My_Heap" 的相关代码在主页博客:堆的概念与实现

#include"MY_Heap.h"
#include<time.h>
void CreateNDate()
{
	// 造数据
	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* fp = fopen(file, "r");

	if (fp == NULL)
	{
		perror("fopen fail!");
		return;
	}

	//根据要取的个数k,创建一个小堆并包含k个数
	//以数组的方式存放
	int* aheap = (int*)malloc(sizeof(int) * k);
	if (aheap == NULL)
	{
		perror("malloc fail!");
	}
	//从文件中读取前k个
	for (int i = 0; i < k; i++)
	{
		fscanf(fp, "%d", &aheap[i]);
		AdjustUp(aheap, i);

	}
	int x = 0;
	while (fscanf(fp, "%d", &x )!=EOF)
	{
		if (x > aheap[0])//当这个数大于堆顶就进堆
		{
			aheap[0] = x;
			Adjustdown(aheap, k, 0);//向下调整
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", aheap[i]);
	}
	printf("\n");
	free(aheap);
	fclose(fp);
	
}
int main()
{
	CreateNDate();
	PrintTopK("data.txt", 5);
	return 0;
}

结语:

       随着这篇关于题目解析的博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。解题的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。

       在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。         你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏、关注这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容,让我们在知识的道路上共同前行。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值