面试收集小技巧之位图实现

之前有很多题目说到要用位图来解决问题,比如,

1.找1到10W之间没有出现的两个数,其中这些数是乱序排放(可能数字比10W还大,比如说40亿)

2.一个最多包含n个正整数的文件,每个数都小于n,其中n=107。如果在输入文件中有任何正数重复出现就是致命错误。没有其他数据与该正数相关联。输出按升序排列的输入正数的列表

3.给出40亿个数,搜索某一个数是否存在于这些数之中

4.两个整数集合A和B,求交集。

 

这里面就有位图的用武之地了,位图的好处是一来位操作比较快,二来占用空间会比较小, 比如说10W个整数,如果全部加载到内存的话大概需要105*4B(大约400KB),但是如果知道这些数最大为105的话,只需要105bit(大约10KB),时间效率和空间效率都有了很大提高。

 

以问题2为例,位图法解题思路如下:
a.分配位图空间,初始每位置零:最多n(n=107)个数,怎么在语言中具体实现这个位图。

b.遍历文件,出现过的整数对应的bit位置为1。

c.顺序遍历位图,为1的bit位的索引按序输出。

 

这个思路在具体实现时,分配空间怎么分?置位操作怎么实现?

对于c语言,可以用整数或者字符数组来模拟这么一个大的位图,以整数为例,申请一个数组int bitmap[1000]即能表示32000个bit位,因为数组是连续存放的,所以可以用来模拟。因此对于最大值和最小值相差为N(N可能非常大)的状况,需要整数数组的大小是N/32.进行置位操作是,首先通过索引定位到位所在整数的位置(若索引为i,那么整数在整数数组中的位置为i/32即i>>5),然后确定这一位在索引到的整数中的哪一位(i%32,即i&0x1F)。具体操作代码如下:

#define MaxCount 100000
int bitmap[1+MaxCount/32];
void set(int index)
{
	assert(index<MaxCount);
	assert(index>=0);
	bitmap[index>>5]|=(1<<(index&0x1F);
}
void reset(int index)
{
	assert(index<MaxCount);
	assert(index>=0);
	bitmap[index>>5]&=(~(1<<(index&0x1F)));
}

而对于C++,还可以用bitset这一数据结构直接来实现。

#include <iostream>
#include<bitset> 
using namespace std;
int main(int argc, char *argv[])
{
    const int max = 10000000;
    
    int n,i;
    bitset<max+1> bit;                     //初始默认所有二进制位为0 
    
    while(scanf("%d",&n)!=EOF)
    {
        bit.set(n,1);                   //将第n位置1               
    }    
    for(i=0;i<=max+1;i++)
    {
        if(bit[i]==1)
            printf("%d ",i);
    }
    return 0;
}
posted @ 2013-04-18 15:14  曾见绝美的阳光  阅读(460)  评论(0编辑  收藏  举报