一,题目:
如何在1MB的空间里面对一千万个整数进行排序?并且每个数都小于1千万。实际上这个需要1.25MB的内存空间(这里所说的空间是考虑用位图表示法时,每一位代表一个数,则1千万/(1024*1024*8) 约为1.25MB )。
1MB总共有838,8608个可用位。所以估计也可以在1MB左右的空间里面进行排序了。
二,分析:
1)基于磁盘的归并排序(耗时间)
2)每个号码采用32位整数存储的话,1MB大约可以存储250 000 个号码,需要读取文件40趟才能把全部整数排序。(耗时间)
3)位图法,采用一个1千万位的字符串表示每个数,比如{0,2,3}表示为 1 0 1 1 0 0 0 0 。(说明:左边第一位表示 0 第二位表示1 第三位表示 2 。如果有则表示为1,否则为0)遍历每一个整数,有则标记为1,否则标记为0。然后按顺序输出每个整数。这种方法实际需要1.25MB内存,如果可以方便弄到内存的话可以采用此种方法。
4)假如严格限制为1MB,可以采用的策略:两次遍历或者除去第一位为0或1的整数。
生成文件代码:
#!/usr/bin/python
import random
def randDif(k,n):
if k>n:
return []
a = list(range(1,n+1))
random.shuffle(a)
return a[:k]
if __name__=='__main__':
list = randDif(1000000, 10000000)
writedata = open("d:\input.db", "wb")
for i in list:
writedata.write(i)
writedata.close()
//*在min和max之间生成count个不重复的随机数
unsigned int *outoforder(unsigned int min, unsigned int max, unsigned int count)
{
unsigned int i;
static unsigned int *arr, *res;
unsigned int irand, tmp;
unsigned int m = max - min + 1;
arr = (unsigned int *)malloc(m * sizeof(unsigned int));
if(arr == NULL)
return NULL;
res = arr;
for(i = min; i < max; i++)
*arr++ = i;
arr = res;
srand(time(NULL));
for(i = 0; i < count; i++)
{
irand = rand()*MAGIC_RAND%m;
tmp = *arr;
*arr = *(res+irand);
*(res+irand) = tmp;
arr++;
}
return res;
}
位图实现内存略超1M:
因为1000w整数空间用位图存放需要大约3个2的23次方bit,1.5M空间,所以不能一次遍历完。就分三次遍历。100w个1到1000w的随机数,排序在win7.2G内存下大概用了95ms.
#include "stdio.h"
#include "stdlib.h"
#include <string.h>
#include <time.h>
/*数组已假定初始化为0,未考虑数组越界*/
static inline void setbit_t(unsigned int arr[], unsigned int dig)
{
*(arr+(dig>>5)) |= (0x1 << dig%32);
}
unsigned int sort_data(FILE *fin, FILE *fout)
{
unsigned int arr[0x20000] = {0};
unsigned int data[0x20000] = {0};
unsigned int m;
unsigned int n;
//unsigned int count = 0; //保存读取的数字个数
unsigned int i, j;
for(j = 0; j < 3; j++)
{
n = 0;
memset(data, 0, 0x20000*4);
memset(arr, 0, 0x20000*4);
while(1)
{
n = fread(data, 4, 0x20000, fin);
if( n < 0)
return -1;
m = n;
while(n--)
{
if((*(data+n) > (0x1<<22)*j) && (*(data+n) < (0x1<<22)*(j+1)))
{
setbit_t(arr, *(data+n)-(0x1<<22)*j);
/*count++;*/
}
}
if( m != 0x20000)
break;
}
n = 0;
memset(data, 0, 0x20000*sizeof(unsigned int));
for(m = 0; m < 0x20000; m++)
{
if(*(arr+m) != 0)
{
for(i = 0; i < 32; i++)
{
if((*(arr+m)>>i) & 0x1)
{
*(data + n++) = m*32 + i + (0x1<<22)*j;
if( n == 0x20000)
{
fwrite(data, 4, n, fout);
n = 0;
memset(data, 0, 0x20000*sizeof(unsigned int));
}
}
}
}
}
fwrite(data, 4, n, fout);
fseek(fin, 0, SEEK_SET);
}
return 0;
}
int main()
{
FILE *fin, *fout;
fin = fopen("d:\input.db", "rb");
fout = fopen("d:\output.db", "wb");
if((fin == NULL) || (fout == NULL))
{
printf("open file error
");
return 0;
}
sort_data(fin, fout);
fclose(fin);
fclose(fout);
return 0;
}
clock_t s_time= clock();
sort_data(fin, fout);
clock_t e_time= clock();
clock_t reltime = e_time - s_time;
printf("times: %ld", reltime);