版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! https://blog.csdn.net/summer_dew/article/details/83892927
【题目】文件A.txt中存储了N个整数(N大于100万),要求仅占用4K内存,对该文件中的整数进行排序,结果输出到B.txt
【思路】百万级别的数据排序,理论上讲,应该需要1M以上的空间。4k也可以做不过效率会差不少
4k字节应该是32768个bit(4*1024*8)
申请4k内存,全部清零
遍历A.txt中的整数,先对0~32767之间的数据进行处理
if 该数存在
该数对应的bit直1
遍历4k内存的bit位,将对应bit为1的数输出到结果文件B.txt
4k内存清零
遍历A.txt中的整数,对32768~62235之间的数据进行处理
if 该数存在
该数对应的bit直1
遍历4k内存的bit位,将对应bit为1的数追加输出到结果文件B.txt
4k内存清零
如此往复重复上面的步骤,直到处理的数据涵盖所有的数据范围
最后B.txt中记录了从小到大的所有数据排序,不会多,也不会少
【代码】C
【代码】C++
#include "stdio.h"
#include "malloc.h"
#include "time.h"
#include "assert.h"
#include <iostream>
#include <bitset>
using namespace std;//交换数组中元素用的--忽略 可以手动交换
#define SIZE 2000000 //200万
int num[SIZE]; //这个数组是用来生成文件A中数据用的
//生成文件 A 200万个数据 ----可以掠过不看
int genrand()
{
int n;
FILE *f=fopen("A.txt","w");
assert(f);
for(n=1;n<=SIZE;n++){//生成2000000个数字
num[n]=n;
}
srand((unsigned)time(NULL));//srand()用来设置rand()产生随机数时的随机数种子。
//参数seed必须是个整数,通常可以利用geypid()或time(0)的返回值来当做seed。
//如果每次seed都设相同值,rand()所产生的随机数值每次就会一样。
int i,j;
for(n=0;n<SIZE;n++){
i=(rand()*RAND_MAX+rand())%SIZE;//rand()*RAND_MAX+rand() 是防止产生的随机数最大值小于2000000
//rand()的范围在0-2的16次方
j=(rand()*RAND_MAX+rand())%SIZE;
swap(num[i],num[j]);
}
for(n=0;n<SIZE;n++){
fprintf(f,"%d ",num[n]);//将数组数据写入文件A中,以空格隔开
}
fclose(f);
return 0;
}
//const int max_each_scan=1024*2;//每次扫描4k内存,int 占2个字节
const int max_each_scan=1024*1024;//为了使效果明显,这里我多用了点空间。测试4K的话放开上面的代码,删掉这句
int main(){
//***************** 数据定义 ***************
int num;//每次读取的数据
//***************** 初始化操作 **************
genrand();//生成文件A
clock_t begin=clock();//计时用的 忽略
bitset<max_each_scan> bit_map; //申请4k的位图
bit_map.reset();
FILE *a=fopen("A.txt","r");
FILE *b=fopen("B.txt","w");
assert(a);//判断a是否为空的 忽略
assert(b);
/****************** 核心代码 ****************
1.第一遍扫描A文件 将0-2048数字对应下标的位图置为1
2.将位图为1的下标写入B文件中
3. 第二遍扫描 2048-4048...
4.重复1和2操作,直到 488个位图(1000000/2048) ;
*/
for(int space=max_each_scan;space<SIZE+max_each_scan;space=space+max_each_scan){
fseek(a,0,0);//指针回指文件A开头
bit_map.reset();//位图数据归0
while(fscanf(a,"%d",&num)!=EOF){//读取文件A中数据,直到文件末尾
if(num>=space-max_each_scan && num<space){//如果数字位于0-4K之间 (其实应该是0-4K的倍数,倍数就是循环的次数,第一次是0-4k,第二次是4K-8k...)
bit_map[num%max_each_scan]=1;//将位图对应下标的数据置为1。 位图就是0和1 组成的。
}
}
for(int i=1;i<=max_each_scan;i++){
if(bit_map[i]){//将位图中该位对应是1的下标+当前搜索的数字块 写入B文件中
fprintf(b,"%d ",space-max_each_scan+i);
}
}
}
clock_t end = clock();//计时用的 忽略
printf("耗时:%d",(end-begin)/CLK_TCK);
fclose(a);
fclose(b);
}