原理:Bit-Map就是用一个位来表示某个元素对应的值。采用bit为单位存储数据,大大的节省了空间。如图所示:
例:假设对0-7内的5个元素{3,5,1,6,4}进行排序(不重复)。我们可以使用Bit-Map来做,要表示8个元素,要1个字节空间(8位),故首先开辟1Byte空间,将里面的每一位都置为0。遍历一次元素,将元素的值对应的位变成1。
现在已经将每一个元素对应的位改为1了,所以现在遍历这些位,将值为1的输出即可得到排序的结果。
实现难点:
假设有数据32,则应该把32对应的二进制位变成1,这个逻辑位置应该是a[1]的最低位。
值32应该是上图中红色的位置。所以要将一个值与位对应起来,就要处理两个位置:字节位置(数组下标)+位位置
32的字节位置是1,位位置是0。
字节位置:数据/32(数据右移5位)得到数组下标
位位置:数据%32(与0x1f进行与操作)
c语言实现:
#include<iostream>
using namespace std;
#define MAX 1000000
#define INDEX 5
#define BIT 0x1f
#define NUM 32
int a[1+MAX/NUM]={0};
void set(int n)//将n的逻辑位的二进制位置置为1
{
a[n>>INDEX]=a[n>>INDEX] | (1 << (n & BIT));
//n>>INDEX,相当于除以32,得到对应下标
//n&&BIT,相当于模32,得到对应的位
//a[n>>INDEX] | (1 << (n && BIT))将对应的位变成1
}
void clear(int n) //将逻辑位n的二进制位置为0
{
a[n>>INDEX]=a[n>>INDEX] & (~(1 << (n & BIT)));
}
bool Isexist(int n)//测试n对应的逻辑位的二进制位是否为1
{
return a[n>>INDEX] & (1<<(n&BIT));
}
//用bit-map表示1000000内的数字,假设是排序
int main()
{
int tmp[]={2,4,33,1,65,35,87,65,43,24,777,555,333,987,6543,34567,32,43323,22344,34432,224};
int len=sizeof(tmp)/sizeof(tmp[0]);
for(int i=0;i<len;i++)
{
set(tmp[i]);
}
for(int i=0;i<=MAX;i++)
{
if(Isexist(i))
{
cout<<i<<" ";
}
}
return 0;
}
运行结果:
Bit-Map应用(排序、查询、去重)
1、给40亿个不重复的unsigned int的整数,没有拍过序,然后给定一个数,如何快速判断这个数是否在这40亿个数中。
分析:如果数是有序的,则可以用二分查找来做,时间复杂度为O(logN),空间复杂度是O(1)。无序的话,就用空间换时间的做法。因为unsigned int 的取值范围就在40多亿,40*10^8/1024/1024/8=476M,故我们可以申请512M的空间,每一位表示一个unsigned int 的数,然后遍历一次将所有树的逻辑位置为1,然后查询一个数,若该数的逻辑位为1,则表示这个数已经存在,否则数不存在。
时间复杂度:O(n),需要遍历一次所有数,将其逻辑位变成1
空间复杂度:根据取值范围确定
优点:运算效率高、占用内存小,如N=10000000,只占用N/8=1250000byte=1.25M
缺点:所有的数据不能重复,故不能对重复的数据进行排序和查询。但是这一特性又可以完成查重的功能,遍历数的时候,检查该逻辑位是否为1,如果已经为1,则表示该数重复。
扩展:布隆筛选器https://blog.csdn.net/ShWe_yayaya/article/details/81834986