用堆实现Top-k
🌟🌟hello,各位读者大大们你们好呀🌟🌟
🚀🚀系列专栏:【数据结构的学习】
📝📝本篇内容:用堆实现Top-k
⬆⬆⬆⬆上一篇:二叉树(二)
💖💖作者简介:轩情吖,请多多指教(> •̀֊•́ ) ̖́-
对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:
1.用数据集合中前K个元素来建堆
前k个最大的元素,则建小堆
前k个最小的元素,则建大堆
2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素,再向下调整,将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。
代码实现如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
void swap(int* x,int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
void Down(int *arr,int parent,int size)
{
int child = (parent * 2) + 1;//假设左孩子比右孩子大
while (child < size)
{
if ((child+1)<size&&arr[child] < arr[child + 1])//通过这样的判断,我们就不用关心具体是左孩子大还是右孩子大了
{
child++;
}
if (arr[parent] < arr[child])
{
swap(&arr[parent],&arr[child]);//进行交换
}
parent = child;
child = (parent * 2) + 1;
}
}
int main()
{
srand((unsigned int)time(NULL));//设置种子
int all;//总的数
int k;//前k个最小的数
printf("想要生成的随机的总数:");
scanf("%d", &all);
printf("想要生成的前多少个最小的数:");
scanf("%d", &k);
FILE* fin = fopen("随机数.txt", "w");//把随机数写到文件里去
if (fin == NULL)//需要判断,是否打开成功
{
perror("fopen fail");
exit(-1);
}
for (int i = 0; i < all; i++)
{
int val = rand()%100+1;
fprintf(fin,"%d\n",val);
}
fclose(fin);
int* arr = (int*)malloc(sizeof(int) * k);//创建一个数组,来存放前k个数据
if (arr == NULL)
{
perror("malloc fail");
exit(-1);
}
FILE* fout = fopen("随机数.txt", "r");
if (fout == NULL)
{
perror("fopen fail");
exit(-1);
}
for (int i = 0; i < k; i++)
{
fscanf(fout,"%d",&arr[i]);
}
//调整数组,使其变为一个大堆
int child= k - 1;
int parent = (child - 1) / 2;
while (parent>=0)
{
Down(arr, parent,k);
parent--;
}
//把文档里剩下的值挨个和大根堆比较,如果小于,则替换大根堆,再向下调整
for (int i = k; i < all; i++)
{
int val;
fscanf(fout, "%d", &val);
if (val < arr[0])
{
arr[0] = val;
}
Down(arr, 0, k);
}
//前k个小的数都在数组里了,打印出来
for (int i = 0;i<k; i++)
{
printf("%d ",arr[i]);
}
}
🌸🌸二叉树(三)的知识大概就讲到这里啦,博主后续会继续更新更多数据结构的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪