[排序] 对文件A.txt中存储了N个整数进行排序(N大于100万)要求仅占用4K内存 - 位图排序

版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! 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.重复12操作,直到 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);
}

猜你喜欢

转载自blog.csdn.net/summer_dew/article/details/83892927