编程珠玑第一章

时间:2022-12-28 23:02:19

http://www.doyourself.com.cn

一,题目:

       如何在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\n");
		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);