用bitmap解决海量电话号码统计问题

#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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值