问题:
一台主机,2G内存,40亿个不重复的没排过序的unsigned int的整数的文件,然后再给一个整数,如何快速判断这个整数是否在那40亿个数当中?
解决法案:
遍历法
如果内存足够将40亿个数全部放到内存中,逐个遍历,此时时间复杂度为O(N).可是现在在内存不足,需要批量读一部分数据到内存然后在做判断,加上I/O操作的时间,时间复杂度远远大于O(N).
这时,性能问题主要集中在I/O操作,和遍历数组上。那么有没有降低时间复杂度的方法呢?答案是肯定的,如果我们假定内存是足够的,只去优化时间,可以得到下面的方法。
直接寻址表法
申请一个4G超大数组char a[0~2*32-1],将文件中出现的数字置为1,没有出现的置为0.
例如文件存在一个整数1000022,就将a[1000022]=1.
a | 0 | 1 | 2 | ...... | 1000022 | ..... | 100000030 | ... | 2*32- 1 |
flag | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 |
这时时间复杂度为O(1),可是空间问题还没有解决。分析下我们的算法,以所需判断的整数为数组下标,用0/1来区分整数是否在。一共用了一个字节来作为标记位,而事实上1-bit就足够标记了。如果能把这部分空间优化掉,4G/8 < 2G 那么就可以解决问题了。看下面的方法。
Bit-Map
将整数映射到bit上,例如整数10,10/8=1,10%8=2,那么就将a[1]的b[2]置为1。这样时间复杂度即是O(1),内存也得到了压缩。
a | 0 | 1 | ...... | 2*32 / 8- 1 |
bit | 0 1 2 3 4 5 6 7 | 0 1 2 3 4 5 6 7 | ...... | 0 1 2 3 4 5 6 7 |
flag | 0 0 0 0 0 0 0 0 | 0 0 1 0 0 0 0 0 | ...... | 0 0 0 0 0 0 0 0 |
BitMap 实现
- <span style="font-family:Microsoft YaHei;font-size:14px;">#define WORD 8
- #define SHIFT 3 移动5个位,左移则相当于乘以8,右移相当于除以8取整
- #define MASK 0x07
- #define N 100000000
- char bitmap[1 + N / WORD];
- /*
- * 置位函数——用"|"操作符,i&MASK相当于mod操作
- * m mod n 运算,当n = 2的X次幂的时候,m mod n = m&(n-1)
- */
- void set(int i) {
- bitmap[i >> SHIFT] |= (1 << (i & MASK));
- }
- /* 清除位操作,用&~操作符 */
- void clear(int i) {
- bitmap[i >> SHIFT] &= ~(1 << (i & MASK));
- }
- /* 测试位操作用&操作符 */
- int test(int i) {
- return bitmap[i >> SHIFT] & (1 << (i & MASK));
- } </span>
BitMap 应用
枚举
1.全组合
字符串全组合枚举(对于长度为n的字符串,组合方式有2^n种),如:abcdef,可以构造一个从字符串到二进制的映射关系,通过枚举二进制来进行全排序。
null --> 000000
f --> 000001
e --> 000010
ef --> 000011
……
abcedf --> 111111
2.哈米尔顿距离
给定N(1<=N<=100000)个五维的点A(x1,x2,x3,x4,x5),求两个点X(x1,x2,x3,x4,x5)和Y(y1,y2,y3,y4,y5),使得他们的哈密顿距离(d=|x1-y1| + |x2-y2| + |x3-y3| + |x4-y4| + |x5-y5|)最大。
搜索
爬虫系统中常用的URL去重(Bloom Filter算法)
压缩
在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数?
给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?
位排序
转载自: http://blog.csdn.NET/liufei_learning/article/details/19303179