0. 何为bitmap
说白了就是一个数组,但是这个数组的定义和使用方式有些区别。他的每一个元素是一个bit。
1. 具体场景
构建一个数字集合,数字范围是1 - 1024,如何快速判断一个数是否在这个集合中。
场景很简单,构建一个int
型的数组arr
就可以了,下标表示对应的数字,如果 a[ 1 ] = 0
表示数字1
不存在,a[1] != 0
,表示数字1
存在。
2. 上边的方式占用多大空间?
一共1024个元素,每个元素都是int
类型,那么一共需要开辟N = sizeof(int) * 1024 个字节
,也就是N= 4096
个字节
3. 改进
上边的int
类型数组,其实每一个元素只标定两种情况 0
和 非 0
,那用bool
类型的数组就更合适一些啊。没错,如果换成bool
数组,也是可以的,需要的空间大小是N / 4
字节,也就是1024
字节。
4. 再次改进
一个bool
型虽然在使用时只表示两种逻辑,即true
和false
,但是实际上底层用了8个bit
。最最基础的,表达true
和false
的应该是一个二进制位,也就是一个bit
。
构建一个bit
数组,实际上就是构建bitmap
了。
如果用bitmap
来实现上边情况的话,需要的空间大小是N / 4 / 8 = 128 字节
。如此可见空间有所节约。
5. c++实现bitmap
c++ code:
#include <iostream>
#include <cstring>
using namespace std;
class bitmap{
public:
bitmap(int _ss){
ss = _ss; // 要存的总数
int_ss = ss / 32 + 1;
ptr = new unsigned int[int_ss];
memset(ptr, 0, sizeof(ptr));
}
~bitmap(){
delete[] ptr;
}
void insert(int x){
int idx = x / 32;
int bit_idx = x % 32;
ptr[idx] |= ( 1 << (31 - bit_idx) );
}
void erase(int x){
int idx = x / 32;
int bit_idx = x % 32;
ptr[idx] &= ~( 1 << (31 - bit_idx) );
}
bool query(int x){
int idx = x / 32;
int bit_idx = x % 32;
if( ( ptr[idx] & ( 1 << (31 - bit_idx) ) ) == 0) return false;
return true;
}
// 打印当前bitmap情况
void print(){
for(int i = 0; i < int_ss; ++i){
printBin(ptr[i]);
}
}
private:
int ss = 0; // 要存储的最大整数
int int_ss = 0;
unsigned int *ptr = nullptr;
void printBin(int x){
for(int i = 0; i < 32; ++i){
printf("%d", (x >> (31 - i)) & 1 );
if((i + 1) % 8 == 0) printf(" ");
}
cout << endl;
}
};
int main(){
// test code
bitmap a(31);
while(1){
int op, x;
cin >> op >> x;
a.print();
if(op == 1) {
a.insert(x);
a.print();
}else if(op == 0){
a.erase(x);
a.print();
}else {
cout << a.query(x) << endl;
}
}
return 0;
}