编程珠玑---第一章 阅读笔记

昨天看了编程珠玑的第一章和课后题目,收获很大,大概总结下。

第一章首先提出了一个问题:如果有一个文件最多n(n=1000w)个整数,这些整数都<n, 并且这些整数是不重复的,但是是无序的,如何使用一种快速的方法将这些整数进行排序?同时要求内存最多是1M,即空间有要求。

问题就这样被提出,书中给出了好几种方法。

第一种,很容易想到的就是使用归并排序,时间复杂度是nlgn。但归并排序需要把数据全部读入内存,1000w个整数的大小是1000w*4/(1024*1024)大约是40M(假设一个整数是4个字节),显然不能将全部数据读入内存。

第二种方法是这样描述的:因为这些整数是<1000w的,那么可以将这些整数分成40组,分别是[0-249999]  [250000-4999999]  … [9750000-9999999],然后遍历40次整数序列,第一次找出范围在[0-249999]的,第二次找出范围在[250000-499999]的。。。第40次找出范围在[9750000-9999999]的。这样时间复杂度是40n,空间复杂度是n/40,比归并要好点。当然也可以把范围扩大或者缩小,比如两次遍历,第一次范围是[0-4999999],第二次是[5000000-9999999],这样空间复杂度会变大。

书中第三种方法应该是很巧妙的,而且很有学习价值,称为位图法。其思想是用1位来表示[0~n-1]中的整数是否存在。1表示存在,0表示不存在。这样的话进行一次遍历,就可以进行排序了,而且空间复杂度是n/(8*1024*1024)。例如对于20个数来说,如果集合是这样的{1,2,3,5,8,13}即表示共6个数,都小于20.那么其位图表示法如下:01110100100001000000.即如果这个数在序列中,那么用1表示,如果不在用0表示,这样就简单的把序列进行了排序,不得不赞这种思想。

这种思想的伪代码如下:

for (i  in  [0~n-1])  bit[i] = 0; //初始化为0

for(i  in [0~n-1])

if (i in input file)(判断i是否在输入中,如果在则设置bit[i]为1)

      bit[i] = 1

for(i  in [0~n-1])

if(bit[i] == 1)(输出i)

     output i

 

这种思想的在利用的时候需要考虑一些问题:

1、需要输入的数是在小于n的情况下,即要有一个范围

2、输入的数是没有重复的,当然如果有重复也是可以的,比如重复次数不超过m次的话,那么可以用lgm位来表示1个数

章节后面有一些习题,也是很好的。

1、如果整数有1000w个的话,其实1000w位的空间是大于1M的,那么如何处理呢?

可以利用第二种思想和位图思想进行结合。

对数据进行两次遍历,第一次找出[0~4999999]的数据,并且用位图进行表示,第二次找出[5000000~9999999]的数据用位图表示,这样就会将空间降到了一半。

编程珠玑第一章主要是这个位图的思想,以后考虑问题尽量想到这样的思想,利用空间换时间,而且尽量减少空间的使用。哈哈~~~

你可能感兴趣的:(编程,File,input,output)