位图
位图一般用来处理大量数据的问题,比如要在100亿个整数中,查找某个数是否存在。第一想到的是遍历的方法,但是遍历首先要往内存中去存储数据,要将100亿个整型直接存储到内存中是做不到的。这时就可以运用到位图。
什么是位图
位图就是创建一个整型A,用这个整型A的bit位去代替一个储存空间,我们都知道比特位只有0和1,如果为了查找数据是否存在,只有两种状态存在和不存在,可以用1和0去表示,比如整型数组:
int array[8] = {0,5,11,21,17,15,26,30};
array存储了8个整型,占用了32个字节。而如果用比特位的0代表没有数据,1代表数据已经存入,可以将所给数据的数值代表比特位的位置,依次将整型A的对应比特位置为1。
位图如何存储数据
以上面的整型数组为例。
位图的相关代码如下:
#define N 8
typedef int BM_TYPE;
typedef struct BitMap
{
unsigned int bit[N];
int size;
}BitMap,*pBitMap;
void InitBitMap(pBitMap BMap);
void InsertBitMap(pBitMap BMap, BM_TYPE d);
void DeleteBitMap(pBitMap BMap, BM_TYPE d);
BM_TYPE FindBitMap(pBitMap BMap, BM_TYPE d);
void InitBitMap(pBitMap BMap)
{
int count = N;
assert(BMap);
BMap->size = 0;
while(count--)
BMap->bit[count] = 0;
}
void InsertBitMap(pBitMap BMap, BM_TYPE d) //增加数据 对应比特位置1
{
int byteNo;
int bitNo;
assert(BMap);
byteNo = d/32;
bitNo = d%32;
BMap->bit[byteNo] |= (1<<bitNo);
}
void DeleteBitMap(pBitMap BMap, BM_TYPE d) //删除数据 对应比特位置0
{
int byteNo;
int bitNo;
assert(BMap);
byteNo = d/32;
bitNo = d%32;
BMap->bit[byteNo] &= ~(1<<bitNo);
}
BM_TYPE FindBitMap(pBitMap BMap, BM_TYPE d) //查找数据
{
int byteNo;
int bitNo;
BM_TYPE NewNo;
assert(BMap);
byteNo = d/32;
bitNo = d%32;
NewNo = BMap->bit[byteNo];
NewNo |= (1<<bitNo);
if(NewNo == BMap->bit[byteNo])
return 1;
else
return 0;
}
由于数据量很大,数据值分布不均匀,可以采用哈希存储的结构。先用哈希函数将数据改变为我们所能保存(比如开辟一个整型只能保存32个数,两个整型可以保存64个数,以此类推)的地址值,再去存储。
位图的变形
普通的位图只能表示0和1,存储数据的两种状态存在和不存在,如果数据有可能出现多次,而要找到只出现一次的数据,就需要对位图进行变形。将之前每个数据只用一位比特位,变成两位比特位。00代表不存在、01代表出现一次、10和11都代表出现多次。
从上图中就可以看出,变形位图明确表示了0、1、6、11都只出现了1次。
变形位图的相关代码:
typedef unsigned int BMD_TYPE;
typedef struct BitMapD
{
BMD_TYPE* arr;
int size;
int capacity;
}BitMapD,*pBitMapD;
void InitBitMapD(pBitMapD bmd);
void InsertBitMapD(pBitMapD bmd,BMD_TYPE d);
void DeleteBitMapD(pBitMapD bmd,BMD_TYPE d);
int CountBitMapD(pBitMapD bmd,BMD_TYPE d);
void DestroyBitMapD(pBitMapD bmd);
void InitBitMapD(pBitMapD bmd)
{
assert(bmd);
bmd->arr = NULL;
bmd->capacity = 3;
bmd->arr = (BMD_TYPE*)malloc(sizeof(BMD_TYPE)*bmd->capacity);
if(NULL == bmd->arr)
{
assert(0);
return;
}
memset(bmd->arr,0,bmd->capacity*4);
bmd->size = 0;
}
void InsertBitMapD(pBitMapD bmd,BMD_TYPE d)
{
int byteNo;
int bitNo;
int tmp;
assert(bmd);
byteNo = (d%(bmd->capacity*16))/16;
bitNo = (d%(bmd->capacity*16))%16;
tmp = bmd->arr[byteNo]; //两个比特位的判断比较麻烦。
if( (((1<<bitNo*2) | tmp)!= bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp)!= bmd->arr[byteNo]) )
bmd->arr[byteNo] = bmd->arr[byteNo] | (1<<bitNo*2);
else if( (((1<<bitNo*2) | tmp) == bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp)!= bmd->arr[byteNo]) )
{
bmd->arr[byteNo] = bmd->arr[byteNo] & ~(1<<bitNo*2);
bmd->arr[byteNo] = bmd->arr[byteNo] | (1<<(bitNo*2+1));
}
else
bmd->arr[byteNo] = bmd->arr[byteNo] | (1<<bitNo*2);
}
void DeleteBitMapD(pBitMapD bmd,BMD_TYPE d)
{
int byteNo;
int bitNo;
int tmp;
assert(bmd);
byteNo = (d%(bmd->capacity*16))/16;
bitNo = (d%(bmd->capacity*16))%16; //两个比特位如何判断
tmp = bmd->arr[byteNo];
if( (((1<<bitNo*2) | tmp)!= bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp)== bmd->arr[byteNo]) )
{
bmd->arr[byteNo] = bmd->arr[byteNo] & ~(1<<(bitNo*2+1));
bmd->arr[byteNo] = bmd->arr[byteNo] | (1<<bitNo*2);
}
else if( (((1<<bitNo*2) | tmp) == bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp)!= bmd->arr[byteNo]) )
bmd->arr[byteNo] = bmd->arr[byteNo] & ~(1<<bitNo*2);
else
bmd->arr[byteNo] = bmd->arr[byteNo] & ~(1<<bitNo*2);
}
int CountBitMapD(pBitMapD bmd,BMD_TYPE d)
{
int byteNo;
int bitNo;
int tmp;
assert(bmd);
byteNo = (d%(bmd->capacity*16))/16;
bitNo = (d%(bmd->capacity*16))%16; //两个比特位如何判断
tmp = bmd->arr[byteNo];
if( (((1<<bitNo*2) | tmp)!= bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp)== bmd->arr[byteNo]) )
return 2;
else if( (((1<<bitNo*2) | tmp) == bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp)!= bmd->arr[byteNo]) )
return 1;
else if( (((1<<bitNo*2) | tmp)!= bmd->arr[byteNo]) && (((1<<(bitNo*2+1)) | tmp) != bmd->arr[byteNo]) )
return 0;
else
return 3;
}
void DestroyBitMapD(pBitMapD bmd)
{
assert(bmd);
free(bmd->arr);
bmd->arr = NULL;
}