topk问题

前言

这道题要求我们在海量的数据里面找出最大的前k个,并且这些数据庞大到难以存储在内存中(本文选用的数据个数为1000000000),以至于只能在硬盘中,通过文件读写的形式放到内存中

一、难点?

无法全部存储

十亿个数据,若全都是整形,那么大约需要4G才能全部存储完,而且在文件中又没办法很好地排序

二、解决方法

在这里插入图片描述

最大的前K个建小堆(因为要把大的沉底)
比堆顶元素大的就替换,看似在堆顶的元素已经是最大的了,但实际上,比他大的还有k-1个在底下

最小的前k个建大堆(因为要把小的沉底)
想要什么类型的数就把什么类型的数沉底

三、代码演示及检验

(文件构建)

//造资源
void test2()
{
    srand(time(0));
    int n = 1000000000;
    const char* txt = "data.txt";
    FILE* fin = fopen(txt, "w");
    if (fin == NULL)
    {
        perror("fopen error");
        return;
    }

    for (int i = 0; i < n; i++)
    {
        int ran = rand() % 10000;
        fprintf(fin, "%d\n", ran);
    }
    //此处为了方便检验,放置了七个最大的数
    //默认topk中的k == 7
    fprintf(fin, "%d\n", 20000);
    fprintf(fin, "%d\n", 20001);
    fprintf(fin, "%d\n", 20002);
    fprintf(fin, "%d\n", 20003);
    fprintf(fin, "%d\n", 20004);
    fprintf(fin, "%d\n", 20005);
    fprintf(fin, "%d\n", 20006);
    
    fclose(fin);
    fin = NULL;
}

正文:

//向下调整
void DownAdjust(int* arr, int size, int parent)
{
    int child = parent * 2 + 1;

    while (child < size)
    {
        //找出两个孩子中最大的
        if (child + 1 < size && arr[child + 1] < arr[child])
        {
            child++;
        }

        if (arr[parent] > arr[child])
        {
            Swap(&arr[parent], &arr[child]);
            parent = child;
            child = child * 2 + 1;
        }
        else
        {
            break;
        }

    }
}

//向上调整
void UpAdjust(int* arr, int child)
{
    
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        if (arr[child] < arr[parent])
        {
            Swap(&arr[child], &arr[parent]);
            child = parent;
            parent = (parent - 1) / 2;
        }
        else
        {
            break;
        }

    }
    
}

//交换两个数
void Swap(HPDataType* a, HPDataType* b)
{
    HPDataType tmp = *a;
    *a = *b;
    *b = tmp;
}


//topk问题
void test3()
{
    int k = 7;
    const char* txt = "data.txt";
    FILE* fin = fopen(txt, "r");
    if (fin == NULL)
    {
        perror("fopen error");
        return;
    }
    
    int * arr = (int *)malloc(sizeof(int) * k);
    if (arr == NULL)
    {
        perror("malloc");
        return;
    }

    //建小堆
    for (int i = 0; i < k; i++)
    {
        fscanf(fin, "%d", arr + i);
        UpAdjust(arr, i);
    }

    int data = 0;
    for (int i = 0; i < 20; i++)
    {
        fscanf(fin, "%d", &data);
        if (data > arr[0])
        {
            Swap(&data, &arr[0]);
            DownAdjust(arr, 7, 0);
        }
    }

    
}

总结

以上就是今天要讲的内容,本篇文章着重讲解了topk问题的解题思路,在力扣以及牛客网中还会有很多类似的题目,今后将会持续更新,敬请关注!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CtrlZ大牛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值