所谓的BitMap就是用一个bit位来标记某个元素所对应的value,由于BitMap使用了bit位来存储数据,因此可以大大节省存储空间。
基本思想:
我们用一个简单的例子来详细介绍BitMap算法的原理。假设我们要对0-7内的5个元素(4,7,2,5,3)进行排序(这里假设元素没有重复)。我们可以使用BitMap算法达到排序目的。要表示8个数,我们需要8位,即1个byte。
1.首先我们开辟一个字节的空间,将这些空间的所有的位都设置为0
2.然后遍历这5个元素,第一个元素是4,因此我们把第五位的值设置为1
3.然后再处理剩下的四个元素,最终1个字节的状态如下图
4.现在我们遍历一次bytes区域,把值为1的byte的位置输出(2,3,4,5,7),这样便达到了排序的目的
从上面的例子我们可以看出,BitMap算法的思想还是比较简单的,关键的问题是如何确定10进制的数到2进制的映射图
MAP映射:
假设需要排序或则查找的数的总数N=100000000,BitMap中1bit代表一个数字,1个int = 4Bytes = 4*8bit = 32 bit, 那么N个数需要N/32 int空间。所以我们需要申请内存空间的大小为int a[1 + N/32],其中:a[0]在内存中占32为可以对应十进制数0-31,依次类推:
a[0]-----------------------------> 0-31
a[1]------------------------------> 32-63
a[2]-------------------------------> 64-95
a[3]--------------------------------> 96-127
......................................................
那么十进制数如何转换为对应的bit位,下面介绍用位移将十进制数转换为对应的bit位:
1.求十进制数在对应数组a中的下标
十进制数0-31,对应在数组a[0]中,32-63对应在数组a[1]中,64-95对应在数组a[2]中………,使用数学归纳分析得出结论:对于一个十进制数n,其在数组a中的下标为:a[n/32]
2.求出十进制数在对应数a[i]中的值
例如十进制数1在a[0]的值为1,十进制数31在a[0]中值为31,十进制数32在a[1]中值为0。 在十进制0-31就对应0-31,而32-63则对应也是0-31,即给定一个数n可以通过模32求得在对应数组a[i]中的值。
3.位移
对于一个十进制数n,对应在数组a[n/32][n%32]中,但数组a毕竟不是一个二维数组,我们通过移位操作实现置1
a[n/32] |= 1 << n % 32
移位操作:
a[n>>5] |= 1 << (n & 0x1F)
n & 0x1F 保留n的后五位, 相当于 n % 32 求十进制数在数组a[i]中的值
代码实现
#include<iostream>
#include<vector>
using namespace std;
int N = 10000000;
int a[10000000/32 + 1] = {0};
class BitMap {
public:
void addValue(int n);
bool exits(int n);
void display(int row);
};
//设置所在的bit位为1
void BitMap::addValue(int n){
//row = n / 32 求十进制数在数组a中的下标
int row = n >> 5;
//相当于 n % 32 求十进制数在数组a[i]中的下标
a[row] |= 1 << (n & 0x1F);
}
// 判断所在的bit为是否为1
bool BitMap::exits(int n){
int row = n >> 5;
return (a[row] & ( 1 << (n & 0x1F))) == 1;
}
void BitMap::display(int row){
cout<<"BitMap位图展示"<<endl;
for(int i=0;i<row;i++)
{
cout<<"a["<<i<<"] ";
int temp = a[i];
for(int j=0;j<32;j++)
{
if(temp & 1)
{
if (j == 31)
cout<<1<<endl;
else
cout<<"1, ";
}
else
{
if (j == 31)
cout<<0<<endl;
else
cout<<"0, ";
}
temp >>= 1;
}
cout<<endl;
}
}
int main(){
int num[] = {1,5,30,32,64,56,159,120,21,17,35,45};
BitMap map;
for(int i=0;i < sizeof(num)/sizeof(num[0]);i++){
map.addValue(num[i]);
}
int temp = 120;
if(map.exits(temp)){
cout<<"temp:"<<temp<<"has already exists"<<endl;
}
map.display(5);
return 0;
}