位图
将一个数据的每一位都来表示一个数,存在为1不存在为0,一个char有8位,或int的32位,通过运算关系可以将每一个无符号整数都映射到每一位上,从而实现大量数据的存储。
笔试题:给40亿个不重复的无符号整数,没脾气郭旭。给一个无符号数,如何快速判读一个数是否在这40亿个数中。
将这40亿个数全部置入位图相应的位上,有为1,没有为0,如果要找的数对应的位上为1,代表该数存在,否则不存在。
void BitMapInit(Bm* bm, size_t len)
{//初始化
assert(bm);
assert(len > 0);
bm->bits=(char*)malloc(sizeof(char)*len>> 3);
memset(bm->bits, 0, sizeof(char)*len >> 3);
bm->len = len;
}
void BitMapDestory(Bm* bm)
{//销毁
assert(bm);
free(bm->bits);
bm->len = 0;
bm->bits = NULL;
}
void BitMapset(Bm* bm,int key)
{//加一个进位图
assert(bm);
int index=0;
int tmp;
index = key >> 3;//找到数据存放在第几个字节内
tmp =key% 8; //确定该值位于该字节的第几位
bm->bits[index] |= 1 << tmp;
}
void BitMapreset(Bm* bm, int key)
{//将一个数清除
assert(bm);
int index = key >> 3;
int tmp = key % 8;
bm->bits[index] &= ~(1 << tmp); //将1左移到该数的位置取反相与
}
void print(Bm* bm, size_t len)
{
assert(bm);
assert(len > 0);
int i = 0;
int j = 0;
for (i = 0; i < bm->len>>3; i++)
{
for (j = 0; j < 8; j++)
{
printf("%d", (bm->bits[i] >> j) & 1);
printf("\n");
}
}
}
int main()
{
Bm bm;
BitMapInit(&bm, 24);//最大位数可以输入-1
BitMapset(&bm, 3);
BitMapset(&bm, 14);
BitMapset(&bm, 6);
BitMapset(&bm, 18);
BitMapset(&bm, 22);
BitMapreset(&bm, 14);
BitMapreset(&bm,22);
print(&bm,24);
BitMapDestory(&bm);
return 0;
}
位图
优点:速度快,内存空间占用小,能表示大范围数据
缺点:
1.可读性差
2.存储元素的个数比一般元素要多,但是存储元素的大小受空间大小的限制。
位图的应用
1.给定100亿个整数,设计算法找到只出现一次的整数
100亿个数据中只出现依次的数据,依旧采用位图的结构,此时由于要判断出现的次数,我们采用两位来表示,00表示不存在,01表示存在依次,10表示存在两次以上。
2.给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集
此时内存明显不够用此时我们将两个文件100亿个数据分别分成1000份,每份文件使用位图存放,然后将两个文件的每一份相与,与完如果对应位上仍旧为一说明有交集
位图变形:
1.1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
我们需要将100亿个数据分成1000份文件,将每个文件的数据通过位图存储,我们采用两个比特位
00:没有出现,01,出现一次,10出现2次,11舍弃,再将这1000个文件中出现出现两次的数据进行输出