文件中找TopK问题

简介: 文件中找TopK问题

1.解题思路

TopK问题即是在众多数据中找出前K大的值,则可以根据堆的性质来实现,但在使用堆之前,我们要想办法先去建立一个堆,那么建立大堆还是小堆?答案是建立小堆.

2.创建一个文件并在文件中写入数据

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 (size_t i = 0; i < n; ++i)
  {
    int x = rand() % 1000000;
    fprintf(fin, "%d\n", x);
  }
  fclose(fin);
}

3.为什么要建立小堆而不建立大堆?

假设数据的范围是1到100,如果要求找出前10大的值,如果我们建立大堆,假设第一个值正好是最大的,那么这个堆里就不会在进入其他的值了,这明显是错误的.

39dbcefb92994c3383b35ce600be84f1.png

但如果建立小堆,每个元素在插入的时候与堆首元素进行比较,如果比首元素大那就替换并向下调整,这样一来,就可以实现我们想要的结果.

4.如何在现有的数据中建立适合的大堆?

我们可以根据K的不同,建立不同大小的堆,加入要找前K个值,那么我们就建立大小为K的小堆,建堆又有两种方式,即向上调整法和向下调整法,在之前的文章中我证明了向上调整法的时间复杂度是O(N*logN)而向下调整法的时间复杂度是O(N),因此如果追求时间复杂的的话,向下调整法会更好

for (int i = (k-2)/2; i < k; i++)
{
  AdjustDown(topK, k, i);
}
/*for (int i = k - 1; i > 0; i--)
{
  AdjustUp(topK, i);
}*/

5.代码实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
void Swap(int* p1, int* p2)
{
  int tmp = *p1;
  *p1 = *p2;
  *p2 = tmp;
}
void AdjustDown(int* a, int n, int parent)
{
  int child = parent * 2 + 1;
  while (child < n)
  {
    if (child+1<n&&a[child + 1] < a[child])
    {
      child++;
    }
    if (a[parent] > a[child])
    {
      Swap(&a[parent], &a[child]);
    }
    parent = child;
    child = parent * 2 + 1;
  }
}
void AdjustUp(int* a, int child)
{
  int parent = (child - 1) / 2;
  while (child > 0)
  {
    if (a[parent] > a[child])
    {
      Swap(&a[parent], &a[child]);
    }
    child = parent;
    parent = (child - 1) / 2;
  }
}
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 (size_t i = 0; i < n; ++i)
  {
    int x = rand() % 1000000;
    fprintf(fin, "%d\n", x);
  }
  fclose(fin);
}
void PrintTopK(const char* file,int k)
{
  int* topK = (int*)malloc(sizeof(int) * k);
  assert(topK);
  FILE* fout = fopen(file, "r");//读取文件 file
  if (fout == NULL) {
    perror("open fail");
    return;
  }
  for (int i = 0; i < k; i++) {
    fscanf(fout, "%d", &topK[i]);
  }
  for (int i = (k-2)/2; i < k; i++)
  {
    AdjustDown(topK, k, i);
  }
  /*for (int i = k - 1; i > 0; i--)
  {
    AdjustUp(topK, i);
  }*/
  int val = 0;
  int ret= fscanf(fout, "%d", &val);
  while (ret != EOF)
  {
    if (val > topK[0])
    {
      topK[0] = val;
      AdjustDown(topK, k, 0);
    }
    ret = fscanf(fout, "%d", &val);
  }
  for (int i = 0; i < k; i++)
  {
    printf("%d ", topK[i]);
  }
  fclose(fout);
}
int main()
{
  CreateNDate();
  PrintTopK("data.txt", 10);
  return 0;
}

实际上,我们可以看出,虽然建堆的时间复杂度可以优化,但是后面的从文件中读取数据并进行判断是否替换的过程是无法进行优化的时间复杂度为O(N*logN),因此建堆的时间复杂度并不影响整个算法的时间复杂度


结尾:今天的分享到此结束,喜欢的朋友如果感觉有帮助可以点赞三连支持,咱们共同进步!

目录
相关文章
|
4月前
|
存储 算法 程序员
topK问题
topK问题
36 2
topK问题
|
11月前
|
C语言
堆排序(Topk问题)
堆排序(Topk问题)
41 0
|
4月前
|
算法 C++
算法--topk问题
该文介绍了TopK问题的两种解决方案:大小根堆和快排分割。使用大根堆可以找到前K小的元素,小根堆则用于找到前K大的元素。示例代码展示了如何用C++实现这两个方法。快排分割通过不断调整数组结构,找到第K大或第K小的元素。文章提供了相应的代码示例及输出结果。
25 0
|
4月前
|
存储 算法 搜索推荐
TopK问题详解
TopK问题详解
|
4月前
TopK问题——用堆来解决
TopK问题——用堆来解决
46 0
|
10月前
|
存储 算法 数据处理
求解TOPK问题
求解TOPK问题
29 0
|
11月前
|
存储 搜索推荐 算法
解密堆排序与TopK问题
解密堆排序与TopK问题
73 0
【TopK问题】——用堆实现
一、TopK问题是什么 TopK问题就是从1000个数中找出前K个最大的数或者最小的数这样的类似问题。 不过并不要求这k个数字必须是有序的,如果题目有要求,则进行堆排序即可。 还有比如求出全国玩韩信前十名等等,排出班级前十名也是TopK问题。
|
存储 Go C语言
堆排序在topK场景题中的应用及原理
堆排序在topK场景题中的应用及原理
116 0
堆排序在topK场景题中的应用及原理
|
算法 搜索推荐 Python
python实现【桶排序】(Bucket Sort)
python实现【桶排序】(Bucket Sort)
python实现【桶排序】(Bucket Sort)