问题:给定输入文件,文件中每条记录是一个整型数(不重复),每条记录最大为n,n<=10000000,要求对文件中所有记录排序(从小到大),然后输入到给定文件。
限制:主存不超过1MB
位图排序就是使用一张表来记录关键字的存在状态(存在或不存在),然后通过采集到的状态(在/不在)通过一次遍历来确定序列顺序。
(1)首先找到该整数对应的数组的下标(i/32)。由于数组中的每一个整数有32位(假设int型为32位),这32位可以表示32个整数。
(2)找到该整数在对应整数的位坐标pos。
(3)设置或清除该整数的位。
1.位向量的实现
#include <stdio.h> #include <stdlib.h> #define SHIFT 5 #define MASK 0x1F #define N 10000000 int a[1 + N/32]; void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); } void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK)); } int test(int i){ return a[i>>SHIFT] & (1<<(i & MASK)); } int main() { int i = 0; //int top = 1 + N/BITSPERWORD; //memset(a, 0, sizeof(a)*sizeof(int)); for( i = 0; i < 100; i++ ) set( i*2 ); for( i = 0; i < 200; i++ ) printf("%d",test(i) ? 1:0 ); puts("/n"); return 0; }
实现说明:
i >> SHIFT:将i向右移动5位,相当于将i除以32位。因为一个int是32位,所以结果表示i在第几个int数组成员中;1 << (i & MASK):使用掩码留下i的低5位相当于获得了余数,标识着在当前int中的第几位,所以相应的把0001中的1移动这么多位到相应的位上,完成置位操作。
2.位排序算法的实现
因为需要对1000000个乱序数据进行位图排序,所以首先要得到0~10000000区间的乱序输入数字序列(没有重复),所以这里首先根据“rand函数”笔记中的方法从0~N中选择m个互异的数字并进行随机交换打乱顺序的方法,获得这个输入序列,其中N和M均为10000000。
#include <stdio.h> #include <stdlib.h> #include <time.h> //#define CLOCKS_PER_SEC 1000 #define BITSPERWORD 32 //int的位数 #define SHIFT 5 #define MASK 0x1F #define N 100 int a[1 + N/BITSPERWORD ]; void set(int i) {a[i>>SHIFT] |= (1<<(i & MASK)); } void clr(int i) {a[i>>SHIFT] &= ~(1<<(i & MASK)); } int test(int i){return a[i>>SHIFT] & (1<<(i & MASK)); } int randint( int a, int b ){ return a + (RAND_MAX * rand() +2* rand()) % (b + 1 - a); } int main(void){ int * arr = (int*)malloc(sizeof(int)*N); int i,j; for(i = 0;i<N;i++){ arr[i] = i ; clr(i); } for(i =0;i<N;i++){ j = randint(i,N-1); // randint(int i,int j) 产生i与j 之间的随机数 int t = arr[i]; //swap(x[i],x[j]):交换x[i],x[j] arr[i] = arr[j]; arr[j] = t; } for(i = 0; i < N; i++){ printf("%d\n",arr[i]); } clock_t start,end; start=clock(); for(i = 0; i < N;i++) set(arr[i]); for(i = 0; i < N; i++){ if(test(i)){ printf("%d\n",i); } } end=clock(); printf("time=%f ms \n",(double)(end-start)/CLOCKS_PER_SEC); return 0; }