位图排序案例

题目:文件A.txt中存储了N个整数(N大于100万),要求仅占用4K内存,对该文件中的整数进行排序,结果输出到B.txt。


先说明下位图排序的思路:

假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复)。那么我们就可以采用Bit-map的方法来达到排序的目的。要表示8个数,我们就只需要8个Bit(1Bytes),首先我们开辟1Byte的空间,将这些空间的所有Bit位都置为0,如下图:

然后遍历这5个元素,首先第一个元素是4,那么就把4对应的位置为1。因为是从零开始的,所以要把第五位置为一(如下图):

接着再处理第二个元素7,将第八位置为1,,接着再处理第三个元素,一直到最后处理完所有的元素,将相应的位置为1,这时候的内存的Bit位的状态如下:

最后我们现在遍历一遍Bit区域,将该位是一的位的下标输出(2,3,4,5,7),

以上借鉴于:http://www.cnblogs.com/Trony/archive/2012/09/01/2667064.html


我的代码---可直接运行:

#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);
}



位图排序有局限性,就是数据不重复,不过我觉得答题应该没问题吧。

如果有更好的方法希望大家能一起探讨。

不知道清不清楚。能力有限,请见谅。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值