💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
- TOP-K问题
-
- 一、题目描述
- [二、 思路:](#二、 思路:)
- 三、代码实现
- 四、时间复杂度和空间复杂度分析
TOP-K问题
一、题目描述
假设有一亿个数据,内存存储不下,而我们只需要这一亿个数据中最大的前K个。
二、 思路:
1.:存前K个数据入堆
从第二个开始,每存储一个数据进来,就对其进行向上调整,使其一直保持为小堆。直到k-1个节点停止存储。
2.再从第K+1个数据开始读取
此时读取的数据就不再往堆中插入了,而是与堆顶元素进行比较,如果比堆顶大,那么就替换堆顶元素,然后进行基于小堆的向下调整。
3.所有数据读取完毕,堆中剩余的K个就是最大的K个数据
三、代码实现
1.随机产生一万个数据,存入文件中。
c
void CreateNDate()
{
// 造数据
int n = 10000000;
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) % 10000000;
fprintf(fin, "%d\n", x);
}
fclose(fin);
}
2.找前K个最大值
c
void PrintTopK(const char* filename, int k)
{
建堆/用a中前k个元素建堆
FILE* fout = fopen(filename, "r");
if (fout == NULL)
{
perror("fopen fail");
return;
}
开辟K个元素空间
int* minheap = (int*)malloc(sizeof(int) * k);
if (minheap == NULL)
{
perror("malloc fail");
return;
}
将前k个元素读入数组minheap
for (int i = 0; i < k; i++)
{
fscanf(fout, "%d", &minheap[i]);
}
用前k个数建小堆,使用从下到上的向下调整方法建堆。
k-1下标的双亲节点是(k-1-1)/2;
for (int i = (k - 2) / 2; i >= 0; --i)
{
AdjustDown(minheap, k, i);
}
将剩余n-k个元素依次与堆顶元素交换,不满足,则替换
int x = 0;
while (fscanf(fout, "%d", &x) != EOF)
{
if (x > minheap[0])
{
替换堆顶元素进堆
minheap[0] = x;
并且进行调整
AdjustDown(minheap, k, 0);
}
}
遍历完所有n个数据后,打印出堆中的数据,就是最大的K个数据啦!
for (int i = 0; i < k; i++)
{
printf("%d ", minheap[i]);
}
printf("\n");
fclose(fout);
}
// fprintf fscanf
3.测试类:
c
int main()
{
//CreateNDate();
PrintTopK("data.txt", 5);
return 0;
}
四、时间复杂度和空间复杂度分析
🔸时间复杂度:O(N*logK);
N
:节点个数。K
:最大的前K个个数
如果N>>K,那么可以认为时间复杂度是O(N)
;这也是此算法的厉害之处。
🔸空间复杂度:O(K);
K
:最大的前K个个数.