位图
所谓位图(bitmap),是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。
例如,要判断一千万个人的状态,每个人只有两种状态:男人,女人,可以用0,1表示。那么就可以开一个int数组,一个int有32个位,就可以表示32个人。操作的时候可以使用位操作。
使用位图法判断整形数组是否存在重复
判断集合中存在重复是常见编程任务之一,当集合中数据量比较大时我们通常希望少进行几次扫描,这时双重循环法就不可取了。位图法比较适合于这种情况,它的做法是按照集合中最大元素max创建一个长度为max+1的新数组,然后再次扫描原数组,遇到几就给新数组的第几位置上1,如遇到 5就给新数组的第六个元素置1,这样下次再遇到5想置位时发现新数组的第六个元素已经是1了,这说明这次的数据肯定和以前的数据存在着重复。这种给新数组初始化时置零其后置一的做法类似于位图的处理方法故称位图法。它的运算次数最坏的情况为2N。如果已知数组的最大值即能事先给新数组定长的话效率还能提高一倍。
代码如下:
BitMap.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef struct BitMap
{
int *_bmp;
int _capacity; //位集合所占空间大小
int _size; //比特位有效个数
}BitMap;
//位图的初始化
void BitMapInit(BitMap* bmp, int capacity);
//将某一位置1
void BitMapSet(BitMap* bmp, int which);
//将某一位置0
void BitMapReSet(BitMap* bmp, int which);
//判断某一位是0还是1
int BitMapTest(BitMap* bmp, int which);
//位图的比特位有效个数
int BitMapSize(BitMap* bmp);
//比特位为1的个数
int BitMapCount(BitMap* bmp);
//位图的销毁
void BitMapDestroy(BitMap* bmp);
BitMap.c
#include "BitMap.h"
//位图的初始化
void BitMapInit(BitMap* bmp, int bitcount)
{
assert(bmp);
bmp->_capacity = (bitcount / 32) + 1;
bmp->_bmp = (int *)malloc(bmp->_capacity * sizeof(int));
if (NULL == bmp->_bmp)
return;
bmp->_size = bitcount;
}
//将某一位置1
void BitMapSet(BitMap* bmp, int which)
{
int index, pos;
assert(bmp);
if (which >= bmp->_size)
return;
index = which / 32; //算出在哪个整形数据中
pos = which % 32; //算出在该整形数据中的哪一位
bmp->_bmp[index] |= (1 << pos);
}
//将某一位置0
void BitMapReSet(BitMap* bmp, int which)
{
int index, pos;
assert(bmp);
if (which >= bmp->_size)
return;
index = which / 32;
pos = which % 32;
bmp->_bmp[index] &= ~(1 << pos);
}
//判断某一位是0还是1
int BitMapTest(BitMap* bmp, int which)
{
int index, pos;
assert(bmp);
if (which >= bmp->_size)
return 0;
index = which / 32;
pos = which % 32;
return bmp->_bmp[index] & (1 << pos);
}
//位图的比特位有效个数
int BitMapSize(BitMap* bmp)
{
assert(bmp);
return bmp->_size;
}
//比特位为1的个数
int BitMapCount(BitMap* bmp)
{
int i = 0;
int count = 0;
const char* bitcount = "\0\1\1\2\1\2\2\3\1\2\2\3\2\3\3\4";
for (; i < bmp->_capacity; i++)
{
int value = bmp->_bmp[i];
int j = 0;
while (j < sizeof(bmp->_bmp[0]))
{
char c = value;
count += bitcount[c & 0x0f]; //先算低四位中1的个数
c >>= 4;
count += bitcount[c & 0xf]; //再算高四位中1的个数
value >>= 8; //计算下一个字节
j++;
}
}
return count;
}
//位图的销毁
void BitMapDestroy(BitMap* bmp)
{
assert(bmp);
if (bmp->_bmp)
{
free(bmp->_bmp);
bmp->_bmp = NULL;
bmp->_capacity = 0;
bmp->_size = 0;
}
}
test.c
#include "BitMap.h"
int main()
{
BitMap bmp;
BitMapInit(&bmp,32);
BitMapSet(&bmp, 3);
BitMapReSet(&bmp, 5);
printf("第一位为:%d\n", BitMapTest(&bmp, 3));
printf("第三位为:%d\n", BitMapTest(&bmp, 1));
printf("位图中1的个数为:%d\n", BitMapCount(&bmp));
BitMapDestroy(&bmp);
system("pause");
return 0;
}