在存有10亿个数的文件中找到最大的100万个数

来源:互联网 发布:php编程教程 编辑:程序博客网 时间:2024/04/30 07:33

这是《编程珠玑》中的一道题目。10亿个整数,假设每个整数需要四个字节,如果使用排序的话,需要大约4G的内存,现在的很多pc都没有多这么内存,更不用说作者那个年代。

我们借助最小堆来解决这个问题。

主要步骤:

一、使用一个大小为一百万零一的整数数组来构建堆(堆的下标从1开始)

二、从文件中读取前一百万个数,每读入一个数,调用函数,保持其最小堆的性质,堆的根永远是堆中最小的元素。

三、从一百万零一个数开始,每读入一个数开始,比较这个数与堆的根比较,如果比根大,就用这个数替换掉根,调用函数,保持最小堆性质。


先生成10亿个随机数,使用的也是《编程珠玑》上的方法,将这10亿个数输出到data.txt中。

#include <stdlib.h>#include <stdio.h>int main(int argc, char *argv[]) {unsigned m, n;printf ("生成m个小于等于n的随机数!,请输入m和n:\n");scanf("%d%d", &m, &n);FILE *fp = fopen("data.txt", "w");/* 生成m个小于等于n的随机数 */unsigned i;for(i = 0; i < n; ++ i){int temp = rand();if((temp  % (n - i)) < m){fprintf(fp, "%d\n", i);-- m;}}fclose(fp);return 0;}

生成了10亿个小于20亿的随机数,并且这10亿个数是不重复的。整个data.txt文件大约有10G,我的系统无法打开,内存不够。

然后就是从这10亿个数中选出前100万个最大的数。

#include <stdio.h>#include <stdlib.h>/* 定义堆的大小 */#define HEAPSIZE 1000000/* 使用数组来构建最小堆 */unsigned num[HEAPSIZE+1];/* 在堆的末尾插入新元素后,保持最小堆性质 */void siftup(int size){int i = size;unsigned parent, temp;while(1){if(i == 1)break;parent = i / 2;/* 已经是最小堆,退出 */if(num[parent] <= num[i])break;/* 交换父亲和儿子 */temp = num[parent];num[parent] = num[i];num[i] = temp;i = parent;}}/* 替换根元素后保持最小堆性质 */void siftdown(int size){int i = 1;unsigned child;while(1){child = 2 * i;if(child > size)break;/* child 是 i 的左儿子 */if(child + 1 <= size){/* 选取两个儿子中比较小的那个 */if(num[child+1] < num[child]){++child;}}/* 已经是最小堆,退出 */if(num[i] <= num[child])break;/* 交换父亲和儿子 */unsigned temp;temp = num[i];num[i] = num[child];num[child] = temp;i = child;}}int main(int argc, char *argv[]) {FILE *fp = fopen("data.txt", "r");unsigned i, number;unsigned count = 0;while(fscanf(fp, "%d", &number) != EOF){/* 前100万个数构建最小堆 */if(count < HEAPSIZE){++count;num[count] = number;siftup(count);continue;}/* 从100万零1个数开始,将当前数与根元素比较 */if(number > num[1]){num[1] = number;siftdown(count);}}fclose(fp);/* 将结果输出到文件中保存 */FILE *result_fp = fopen("result.txt", "w");for(i = 1; i <= HEAPSIZE; ++i){fprintf(result_fp, "%d\n", num[i]);}fclose(result_fp);return 0;}

前100万个数使用siftup函数构建最小堆,而后的数与堆的根比较,如果比根大,则替换掉根,并使用siftdown函数保持最小堆性质。

(如有疏漏之处,欢迎指正!)

原创粉丝点击