#include "stdafx.h"
#include <iostream>
using namespace std;
int const nArraySize = 100000000 / (sizeof(int)*8) + 1;
int Bitmap[nArraySize];
void MapPhoneNumberToBit(int nNumber)
{
Bitmap[nNumber / (8*sizeof(int))] |= 0x00000001<<(nNumber%(8*sizeof(int)));
}
int _tmain(int argc, _TCHAR* argv[])
{
memset(Bitmap,0, nArraySize * sizeof(int));
char pszInputA[9];
do
{
memset(pszInputA,0,sizeof(char)*9);
cout<<"Input phone number. Must be 8 numbers"<<endl;
cin>>pszInputA;
pszInputA[8] = 0; //截断多于8个数字的部分
}
while(strlen(pszInputA) != 8);
int nNumber = atoi(pszInputA);
MapPhoneNumberToBit(nNumber);
return 0;
}
为准备某几个大公司的笔试,看到这样一个问题:
已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
我所拜读的材料里提到了用bitmap解决这种问题,也就是说:
每一个电话号码被映射到了不同的位。
例如:
61234567 对应位 0x00001000
61234568 对应位 0x0001 0000
这样,每一个电话号码也就有了它自己的唯一标识,而且这个标识只占用1位,如果电话号码被统计过,这个位就标识为1,否则标识为0。
最后,通过统计bitmap中被标记为1的个数,就能统计出来不同号码的个数。
已知电话号码是8位,于是相当于范围是从00000000 ---> 9999 9999,这样无非需要 1亿个bit,也就是95.3M的内存。
对这一方法佩服的五体投地的同时,我思考了这样一个问题,这个映射函数怎么搞?每一个电话号码都要对应一个位,怎么让它们彼此对应起来呢?
这个问题其实不难解决:
电话号码00000000为最低位的标记,也就是0x0000.......000001。
那么电话号码00000001就应该是 0x0000.....0000010。
于是电话号码00000002就是0x0000....0000100。
想到这里,我高呼一声,我了个去!电话号码 不就是1这个数字左移位所应该对应的次数么。
于是,我们现在用一个int型的数组来存bitmap,于是每一个元素就是四个字节,对应32位。
现在,用电话号码记作P。
P / 32 就是应当标记该号码的bitmap数组下标,P mod 32 就是1这个数字对应的左移次数,最后,左移完的结果和当前数组下标的记录按位或,这事就结束了……
来段代码就是:
总结:
Bitmap擅长对应于寻找
某个数据是否在集合中出现过的问题
那几个数据出现在某个集合而没有出现在另一个集合的问题
难点:
映射函数很难搞,类似于上面这种超级简单的映射函数的情况可不是很多。
因此:
bitmap最好用来处理那些数据具有一定规律的(例如电话号码每次都可以移位,再比如IP地址也是可以这样映射)海量数据。杂乱无章不容易一眼看出规律的数据不太适合bitmap