40亿个数问题

这个CSDN上看到的腾讯面试题,总算是搞清楚了!

以下转:

一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数

4个字节表示的整数,总共只有2^32约等于4G个可能。
为了简单起见,可以假设都是无符号整数。
分配500MB内存,每一bit代表一个整数,刚好可以表示完4个字节的整数,初始值为0。基本思想每读入一个数,就把它对应的bit位置为1,处理完40G个数后,对500M的内存遍历,找出一个bit为0的位,输出对应的整数就是未出现的。
算法流程:
1)分配500MB内存buf,初始化为0
2)unsigned int x=0x1;
for each int j in file
buf=buf|x < <j;
end
(3) for(unsigned int i=0; i <= 0xffffffff; i++)
if (!(buf & x < <i))
{
output(i);
break;
}
以上只是针对无符号的,有符号的整数可以依此类推。

该题有两种比较优良的算法。。其中一种就是楼上所述的位图操作。。另一种就是使用很少的内存,预料不到的二分法,因为不存在的数必然在最大数和最小数及中间数的两个范围里,必然较小的范围里,通过不断缩短范围,就可以求出来。。。。
这里只给出第一种算法。。
详细见《编程珠玑》
位图运算
/* Copyright (C) 1999 Lucent Technologies */
/* From 'Programming Pearls' by Jon Bentley */
/* bitsort.c -- bitmap sort from Column 1 * Sort distinct integers in the range [0..N-1] */
#include <stdio.h>
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/BITSPERWORD];
void set(int i) { a[i>>SHIFT] |= (1 < <(i & MASK)); }
void clr(int i) { a[i>>SHIFT] &= ~(1 < <(i & MASK)); }
int test(int i){ return a[i>>SHIFT] & (1 < <(i & MASK)); }
int main(){
int i;
for (i = 0; i < N; i++)
clr(i);
while (scanf("%d", &i) != EOF)
set(i);
for (i = 0; i < N; i++)
if (test(i))
printf("%d\n", i);
return 0;
}

====================================================

本文是在
http://blog.csdn.net/king821221/archive/2008/01/20/2054353.aspx
结合自己总结完成的
感谢csdn 感谢...
案例1 :假设一个文件中有9亿条不重复的9位整数,现在要求对这个文件进行排序。
方法:bit 位操作
首先

32位机的寻址能力是 2的32次方, 即4G.寻址能力最大是这样了.
一个最大的9位整数为999999999
这9亿条数据是不重复的

声明一个bit数组,长度为10亿

一共需要10亿 / 8 / 1024 /1024 =120M


把内存中的数据全部初始化为0
读取文件中的数据,并将数据放入内存。比如读到一个数据为341245909这个数据,那就先在内存中找到341245909这个bit,并将bit值置为1
遍历整个bit数组,将bit为1的数组下标存入文件

然后再遍历一次,找出不为零的就可以了.

注意:

如果是有重复的数字,

需要考虑重复的情况

如果普遍多于2个,那么就要设置包含2个bit的数组

或者使用bitmap类型.

案例2

最快的方法找出一篇文章中各个字符的出现次数

声明数组int[256]

以该字符的aci码作为下标即可

案例3 全排列

a,b,c ,d, e 的所有排列

令a =1 ,b = 2,c = 3,...

那么从12345到54321的所有数打印出来就可以了

如果有别的限制,比如ac不相邻

那么就再转换成字符串判断好了.

案例4 组合

a b c d e 5个字母中选3个的组合

可以使用

a b c d e      ----- 数组R(i)

a b c d e      ------数组S(j)

a b c d e      -------数组T(k)

模拟5进制的加法,R,S,T下标从0开始,然后T下标加一,加到5的话就让s下标加一

还有,既然是组合,就要保证s的下标从R的开始,T的从S的开始

for ( i = 0 ;i< 5;i ++)

for (j =i ;j< 5;j++)

for (k = j;k<5;k++)

...{

     //打印R(i)S(j)T(k)

}

案例5 把m个球分n组

0 1 2 ... m

...

0 1 2 ... m

总共n行

模拟M进制的加法即可

(其实和回溯法一个原理,只是这个更好理解)

案例6 换零钱问题

有足够的 1元,5元,10元,20元硬币

组合成170元有多少方法?


其实就是解方程

1 * x1 + 5 * x2 + 10 * x3 + 20 * x4 = 170

然后试解循环法解 x1,x2,x3,x4

案例6   一个文件中有40亿个整数,每个整数为四个字节,内存为1GB,写出一个算法:求出这个文件里的整数里不包含的一个整数

:如果采用bit数组,40亿个bit也就120*4 = 480M 的空间,所以1G绰绰有余.

而40亿的整数占用的是480M * 32 = 15360M 即大约15G, 问题是怎样把这数字读进来

可以一个一个的读.

另外csdn上有个方法,不知道在这里有什么帮助,不过原理还是不错:


使用分段的方法:

因为4字节的整数可以用16进制表示为

00000000H 到 FFFFFFFFH

我们可以分成1000H为一段,把整数分割,

统计每个区间的占有情况

如果是1000H.那么统计不包含的数字就略过这个区间好了

但是这个前提还是要读进来吧?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值