A题:给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数。

1、在文件中至少存在这样一个数?

2、如果有足够的内存,如何处理?

3、如果内存不足,仅可以用文件来进行处理,如何处理?

答案:

1 int 为32位有(expt 2 32) 4294967296 42亿多个数,由于现在数只有40亿,所以必然有整数缺少了。

2.如果采用bitmap位数思想来存放,则32位整数最多需要占用43亿个位。约512MB的内存空间  (2`32/8=512MB)

可以采用前一章的位处理方法。然后判断每个int是否等于-1。因为-1的二进制表示是全1的。如果不等于-1。那么说明某一位没有置位。需要进行处理。

3.

我们从表示每个整数的32位的视角来考虑二分搜索,算法的第一趟最多读取40亿个输入,并把起始位为0的整数写入一个顺序文件,

把起始位为1的写入另一个顺序文件。

当前输入-->0/1探测---》(分2种:为0的位和为1的位)

这2个文件中,有一个文件最多包含20亿个整数,我们接下来将该文件用作当前输入并重复探测过程,但这次探测的是第二个位。如果原始的输入文件包含n个元素,那么第一趟将读取n个整数,第二趟最多读取(n/2)个整数,第3趟最多(n/4)个整数。依赖类推,所以总的运行时间正比于n。通过排序文件并扫描也能找到,但是会导致运行时间正比于nlogN。

(对上面的话不是很认同,假如有很多重复元素怎么办)

这是一种分治思想:

按最高位分为两段,没有出现的那个数,肯定在比较小的段里面。

如果比较少的段最高位为1,那么缺少的那个数的最高位也为1.

如果比较少的段最高位为0,那么少的那个数的最高位也是0.

依次按以上方法去处理每个位。

算法复杂度为O(n)。每次处理的部分都是上一次的一半。累加之后是O(n).

思想与找第K小数的思想是一样的。只不过在这里是有一个自动分割的过程。而找第k小数的时候,是随机找一个数。

通俗解释:

那么我们把情况说得简单一点,假设一个文件里头有10个4bit的整数, 
  1 2 3 4 5 7 6 9 8 10 
  那么找出遗漏的数字。因为2^4=16 所以文件中的10个数字必定有遗漏 
   
  那么我取出一个数字,如果是最高位为1,那么放到一个文件1中,否则放到另外一个文件0中。 
  理论上最高位为1的4bit数字有多少?2^3=8个 
  在分拣到文件的过程中,程序有两个计数器,分别记录放入连个文件的数字的个数,如果其中有一个(也可能两个都是)分拣过去的个数小于8个,那么遗漏的数字肯定在这堆里头。 
  分拣出来 
   
  高位为0: 1 2 3 4 5 6 7 
  高位为1: 8 9 10 
   
  高位为0计数器为 7 高位为1计数器为3 显然这两堆都遗漏了数字(比如第一堆遗漏了0) 
  选择遗漏的那一堆,如此再分拣次高位为1跟为0的…… 
   
  磁盘文件可以交替使用,所以占用的空间也不大 
  关键省却了把整个数据文件读到内存撑爆内存排序然后查找的暴力方法

如果有重复的数据怎么办,假设数据是9个7,一个8?

       比如第一次找,
       高位为0,7 7 7 7 7 7 7 7 7
       高位为1,8
       那选择个数少于16/2=8的那组数据继续就能找到,这里对第二堆数据(只有8,说明高位为1的只有一个数)很快就找到了9,10,11,12,13,14,15都是缺失的。

写的很清楚了,从第一位开始探测,根据是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次方个,不合题意),故选择到的一类,定是缺了某个数的一类。

上面转自:http://blog.csdn.net/burningsheep/article/details/7814591

一篇文章:

分析:32位整数一共有4294967296个,略大于40亿。即使不重复出现,它们也不可能全部放入这40亿个整数的数组中,必然有一部分不出现。根据二分思想,我们把40亿个数的集合分成两个,其中必然有一个至少缺少一个数的集合,进行递归求解。划分的依据是按数的位扫描,从第31位开始,分别统计这一位是0和1的数,把较小的那一部分用做下一次递归。扫描完第0位,必然得到一个不含元素的空集,这个集合对应的就是缺失的元素。

  为了演示这一过程,我编写了相应的测试程序。由于包含大量的文件I/O操作,看上去比较复杂,但是基本的思想框架是一样的。为了简化起见,只处理30000个带符号的正数(这意味着我从每个数的第14位开始检测,最多有37628个可能),运行前需要生成一个含有30000个数的文件output.txt。

#include <stdio.h>
#include <assert.h> int BitCheck(int total,int n,int last) {
FILE *input,*output0,*output1;
char filename[] = "";
int mask,value,num0 = ,num1 = ;
assert(n>=);
if(n==total)
input = fopen("40亿output.txt","r");
else {
sprintf(filename,"%d_%d.txt",n,last);
input = fopen(filename,"r");
}
if(n==) {
sprintf(filename,"final_0");
output0 = fopen(filename,"w");
sprintf(filename,"final_1");
output1 = fopen(filename,"w");
}
else {
sprintf(filename,"%d_0.txt",n-);
output0 = fopen(filename,"w");
sprintf(filename,"%d_1.txt",n-);
output1 = fopen(filename,"w");
}
assert(input!=NULL && output0!=NULL&&output1!=NULL);
mask = <<n;
while(!feof(input)) {
fscanf(input,"%d\n",&value);
if(value&mask) {
fprintf(output1,"%d\n",value);
num1++;
}
else {
fprintf(output0,"%d\n",value);
num0++;
}
}
fflush(output0);
fflush(output1);
fclose(output0);
fclose(output1);
fclose(input);
return num1<num0;
} int Search(int n){
int total = n,last = ,missing =;
while(n>=) {
last = BitCheck(total,n,last);
missing |= (last<<n);
n--;
}
printf("missing number:%d\n",missing);
return ;
} int main() {
Search();
return ;
}

上面的代码,第14位开始检测,最多有37628个可能,因为2^14+2^13+.......1为32768.所有从第14为开始检测完全可以查找

30000里面丢失的数。

last=BitCheck(total,n,last)

last为上次检查的结果,0或1.

while循环一直到n为0为止。

转自:http://www.cnblogs.com/wuyuegb2312/p/3139926.html

http://hi.baidu.com/banyantree/item/904da2e81626bf0e570f1d3e
http://blog.csdn.net/ju136/article/details/6839100
http://www.cnblogs.com/wuyuegb2312/p/3139926.html

《编程珠玑》第二章 aha算法的更多相关文章

  1. 编程珠玑第一章的算法,Java实现,通俗易懂

    该算法也就是所谓的位图算法,用一个int表示32位,也就是实际值为1~32的数. 按照书里说的, 该算法只适合内存有限,而磁盘和时间不限,且数字在1~MAX之间不重复的排序. package demo ...

  2. 3-8《Ruby元编程》第二章对象模型

    <Ruby元编程> 第二章 对象模型 类定义揭秘inside class definitions: class关键字更像一个作用域操作符,核心作用是可以在里面随时定义方法. [].meth ...

  3. [书籍翻译] 《JavaScript并发编程》 第二章 JavaScript运行模型

    本文是我翻译<JavaScript Concurrency>书籍的第二章 JavaScript运行模型,该书主要以Promises.Generator.Web workers等技术来讲解J ...

  4. <编程珠玑>笔记 (一) 问题-算法-数据结构

    1  精确描述问题 第一章强调的重点在于”精确的描述问题“,这是程序开发的第一步 -- "Problem definition" 1.1  Precise problem stat ...

  5. java多线程编程核心技术——第二章

    第一节synchronized同步方法目录 1.1方法内的变量为线程安全的 1.2实例变量非线程安全 1.3多个对象多个锁 1.4synchronized方法与锁对象 1.5脏读 1.6synchro ...

  6. java多线程编程核心技术——第二章总结

    第一节synchronized同步方法目录 1.1方法内的变量为线程安全的 1.2实例变量非线程安全 1.3多个对象多个锁 1.4synchronized方法与锁对象 1.5脏读 1.6synchro ...

  7. [Java编程思想] 第二章 一切都是对象

    第二章 一切都是对象 2.1 用引用操纵对象   创建一个String引用: String s;   这里所创建的只是引用,并不是对象.   创建一个引用的同时便初始化: String s = &qu ...

  8. [编程笔记]第二章 C语言预备知识

    /*第二讲 C语言预备专业知识 1.CPU 内存条 硬盘 显卡 主板 显示器之间的关系 CPU不能直接处理硬盘上的数据 文件存储在硬盘,当运行时,操作系统把硬盘上的数据调用到内存条上. 图像以数据的形 ...

  9. 《C专家编程》第二章——这不是Bug,而是语言特性

    无论一门语言有多么流行或多么优秀,它总是存在一些问题,C语言也不例外.本章讨论的重点是C语言本身存在的问题,作者煞费苦心的用一个太空任务和软件的故事开头,也用另一个太空任务和软件的故事结尾,引人入胜. ...

随机推荐

  1. 【转】 ubuntu下fastboot找不到devices

    原文网址:http://memory.blog.51cto.com/6054201/1202420 转载补充: 1.首先,手机必须先进入bootloader状态,fastboot devices才能有 ...

  2. C# 知识点收集

    1. 数组复制 byte[] source; byte[] dest; int srcOffset = 0; int dstOffset = 0; int count = 10; System.Buf ...

  3. c++ 07

    一.多重继承 1)子类同时拥有两个或两个以上的基类,同时继承了所有基类的属性和行为. 销售员    经理       \  /     销售经理 汽车 客用特性 商用特性    \    |    / ...

  4. HTTP请求&&响应

    在视频上截的图....俗话说好记性不如烂笔头,所以就保留下来 请求: 响应: 状态码: 请求头和响应头的解释:

  5. Linux usb子系统(二):USB设备驱动usb-skeleton.c

    usb驱动分为通过usbfs操作设备的用户空间驱动,内核空间的内核驱动.两者不能同时进行,否则容易引发对共享资源访问的问题,死锁!使用了内核驱动,就不能在usbfs里驱动该设备. 下面转载的一篇分析u ...

  6. Block内的强引用

    众所周知,当某个对象持有着一个Block的时候,如果在Block内部使用强引用反过来持有这个对象,就会导致引用循环.为了避免引用循环,可以使用__weak修饰符,苹果的官方文档在用代码演示__weak ...

  7. Apache、Tomcat、JBoss、WebLogic的区别与关系

    Weblogic: 是一个企业级的应用服务器,其中包括j2ee中的各类应用如jsp,servlet,ejb等 Tomcat:   是一个初级的应用服务器,支持sp和servlet,不支持EJB,如需E ...

  8. [SASS] Make a responsive arrow box

    Check the page:http://www.cssarrowplease.com/ In HTML: {{type}} is tow way binding in Angular, three ...

  9. Tomcat 常见问题篇

    Tomcat 常见问题一.Tomcat常见问题 1.Tomcat web容器出现故障时,我们通过Tomcat自带的logs查看原因,以下错误提示都是源于logs 2.Connection refuse ...

  10. .net 导出

    public void CreateExcel(DataTable dt, string fileName) { HttpResponse resp = System.Web.HttpContext. ...