什么是Top-K问题问题呢?
?
此时你是否感觉好像会一点了。有了模糊的思路?
那么我们继续,堆解决的话,我们首要任务就是建堆,那么如何建呢?所有元素都放一起去建堆吗?那肯定不行啊,所以我们是不是可以先用前K个元素来建堆,然后通过后续调整来实现我们的目标呢?
建K个元素的堆已经明确了,假如我们的目标是找最大的K个元素,问题来了,我们是建大堆还是小堆?你不妨想想?
?
我告诉你吧,我们这里要建小堆,为什么?
如果你是建的大堆,再向里面进元素的话,你是不是要调整啊,那么你肯定要比较吧?我问你,你和谁比呢?堆顶吗?向下调整法然后删除谁呢?是不是感觉很难实现,这种可能可以成功,但是肯定是建小堆简单,不信?看好了哈
接下来开始我的表演了
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <assert.h>
void Print(int* arr, int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void Swap(int* p1, int* p2)
{
int* tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void Adjustup(int* arr, int child)
{
assert(arr);
int parent = (child - 1) / 2;
while (child > 0)
{
if (arr[child] < arr[parent])
{
Swap(&arr[child], &arr[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void Adjustdown(int* arr, int n, int parent)
{
assert(arr);
int child = parent * 2 + 1;
while (child < n)
{
if ((child + 1 < n) && (arr[child + 1] < arr[child]))
{
child++;
}
if (arr[parent] > arr[child])
{
Swap(&arr[parent], &arr[child]);
parent = child;
child= parent * 2 + 1;
}
else
{
break;
}
}
}
void TopK(int k)
{
//第一步:打开文件,找到要的数据
FILE* pf = fopen("data.txt", "r");
//判断是否打开失败
if (pf == NULL)
{
perror(pf);
return;
}
//第二步:建里一个K个大小的小堆(注意我们是找最大的K个数)
//由于我们空间为空,首先我们我们先开辟空间
int* head = (int*)malloc(sizeof(int) * k);
//检查开辟成功与否
if (head == NULL)
{
perror(head);
return;
}
//开始建小堆,小堆!!!(提醒)
for (int i = 0; i < k; i++)
{
fscanf(pf, "%d", &head[i]);
//我们要对其进行调整
Adjustup(head, i);
}
//第三步:我们要开始读取后面的元素,比较后看看能否放入堆中
int x = 0;
while ((fscanf(pf, "%d", &x)) != EOF)//这里我们一定要注意:fscanf是继续上次读取的位置继续读
{
//由于我们建的是小堆,如果比堆顶大的话,一定是可以放入堆中
if (x > head[0])
{
head[0] = x;
Adjustdown(head, k, 0);
}
}
//第四步:输出最大的K个元素
Print(head, k);
//第五步:关闭文件,指针指向空
head = NULL;
fclose(pf);
}
int main()
{
//Creat();
int k = 5;
TopK(k);
return 0;
}
如果你对堆不是有了一定的学习,肯定看不懂这个代码,但是如果你写过堆实现和堆排序,上面代码你肯定可以理解,如果你想学堆实现和堆排序,可以看看我之前写的:
如果你文件操作也不会的话,我也有:
希望你可以实现它们,加油!
void Creat()
{
int n = 10000000;
srand((unsigned int)time(NULL));
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror(pf);
return;
}
//实现产生随机数
for (int i = 1; i < n; i++)
{
//注意:随机数只有三万个左右,所以我们通过+i来调整
int x = (rand() + i) % 10000000;
fprintf(pf, "%d\n", x);
}
//关闭文件
fclose(pf);
pf = NULL;
}
这个是我用来验证代码的,设立了这个文件之后,你可以去里面设置你可以验证自己代码正确性的数据。
最后:
我们强调下:
希望我们可以继续加油,努力学习吧!