《编程珠玑》第二章2.1的三个问题中,有个问题是这样的:
给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数(在文件中至少缺失一个这样的数——为什么?)。
1、如果有足够的内存,如何处理?
2、如果内存不足,仅可以用几个外部的临时文件来进行处理,如何处理?
主要关注第二个问题,在仅有几百个字节的内存下,如何借助外部的“临时”文件解决该问题?
第二章主要对于二分法进行研究,故使用二分法,给了我们一个很好的答案。
写的很清楚了,从第一位开始探测,根据是0或1进行分组,对包含的整数个数不大于N/2的序列继续进行探测,只要搜索到某个位数时,有个分组为的整数个数为0,那么便成功找到缺少的数。
考虑一个极端情况,以对3位的整数进行查找为例。
有如下8个3位的整数:0、1、2、3、4、4、6、7。
以二进制表示是:
000
001
010
011
100
100
110
111
若用以上方法:则会造成探测第一位的时候,有4个0、4个1,按照以上说法“第二趟最多读取n/2=4个元素”可见,0是符合的,所以,进入第一位为0的4个整数中进行搜索,于是,导致第一步就走错了…
要探测该序列,在探测第一位时,发现分组个数一样,故无法进行舍弃;在探测第二位时仍需探测全部的8个数,而探测第二位时,0与1的个数仍相同,也无法舍弃;最终只能通过末位进行判定,而对末位,即使知道了有3个是0,5个是1,缺少的是以0结尾的数,也无法确切的知道整个整数是什么,因为第1、2位都无法确定应是1或0.
之所以会有这种情况,是因为在处理倒数第N位时,
1、
有大于等于2的N次方个数
2、
根据0或1进行分组时,分组包含的数字个数一样,且有个分组包含了所有的01序列组合。(如上面的倒数第三位为0的序列)。
于是,导致无法进行缩减,若运用作者提供的方法,则很有可能会出现错误。
回到原题,若判定的后N位数,恰好是这样的情况,该当如何?
解决:若有这种情况,压根不会进入这个一类中探测。可以模拟一个4位数的数列尝试。
如果一个序列的后N位至少含2的N次方个不相同的数,那么倒数第n+1位(不论是0或1)的这一类至少有2的n次方个整数,则定不会选择该类继续(若选择该类,说明另一类含有的整数数量不小于他,那么总数一定大于2*2的n次方个,不合题意),故选择到的一类,定是缺了某个数的一类。