一、位图
所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。
在这里我们可以借助vector作为位图底层实现载体,具体实现方式如下:
#pragma once
#include<vector>
#include<iostream>
using namespace std;
class BitMap
{
public:
BitMap(size_t bitSet = 10)
:_bitsize(bitSet)
{
_bit.resize((bitSet >> 5)+1);
}
void Set(size_t BitPos)//指定bit置1
{
size_t index = (BitPos >> 5);//定位到具体的int中
if (index<_bitsize)
_bit[index] |= 1 << (BitPos % 32);
}
void SetZero(size_t BitPos)//指定比特位置0
{
size_t index = BitPos >> 5;
if (index < _bitsize)
_bit[index] &= ~(1 << (BitPos % 32));
}
bool Isone(size_t BitPos)//判断指定比特位是否为1
{
size_t index = BitPos >> 5;
if (BitPos < _bitsize)
return _bit[index] & (1 << (BitPos % 32));
cout << "当前比特位不存在" << endl;
return false;
}
size_t CountOf1()const//计算比特位中1的个数
{
char* pBitCount = "\0\1\1\2\1\2\2\3\1\2\2\3\2\3\3\4";
size_t count = 0;
for (int i = 0; i < _bit.size(); ++i)
{
int value = _bit[i];
int j = 0;
//处理一个int
while (j < sizeof(int))
{//处理一个字节中1的个数
count += pBitCount[value & 0X0F];
value >>= 4;
count += pBitCount[value & 0X0F];
value >>= 4;
++j;
}
}
return count;
}
size_t Size()//位图的位数
{
return _bitsize;
}
private:
std::vector<int> _bit;
size_t _bitsize;//总的比特位的个数
};
测试函数:
void TestBitMap()
{
BitMap bt(100);
bt.Set(12);
bt.Set(45);
bt.Set(56);
bt.Set(66);
cout << "位集合中1的个数:" << bt.CountOf1() << endl;
cout << "比特位的个数是:" << bt.Size() << endl;
if (bt.Isone(12))
cout << "12号位置为1" << endl;
else
cout << "12号位置不为1" << endl;
bt.SetZero(66);
cout << "位集合中1的个数:" << bt.CountOf1() << endl;
cout << "比特位的个数是:" << bt.Size() << endl;
if (bt.Isone(50))
cout << "50号位置为1" << endl;
else
cout << "50号位置不为1" << endl;
}
int main()
{
TestBitMap();
system("pause");
return 0;
}
运行结果验证:
二、位图的应用
1、给定100亿个整数,设计算法找到只出现一次的整数 。
解决思路:将100亿个数分拆成1000份文件,再将每份文件里使用位图,并用两位bit表示数字出现的次数,00存出现0次的数,01存放出现1次的数,10存放出现多次的数,11舍弃,再将1000份中出现一次的数全部合并到一个文件里存放即可。
2、给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集
解决方法:扫描每个整数是否出现过,节省内存方法使用bitmap。用两位bit表示数字出现的次数,00表示文件均没出现,10表示文件1出现过,01表示文件2出现过,11表示两文件均出现过,共需要2^32*2/8 = 1GB内存,遍历两个文件中的所有整数,然后寻找bitmap中11对应的整数即是两个文件的交集,这样即可线性时间复杂度完成。
3、1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数
解决方法:将100亿个数分拆成1000份文件,再将每份文件里使用位图,并用两位bit表示数字出现的次数,00存出现0次的数,01存放出现1次的数,10存放出现2次的数,11舍弃,再将1000份中出现次数不超过二的数全部合并到一个文件里存放即可
4、给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法?
精确算法:
将两个文件分别存入相同哈希算法的1000个哈希桶(共两千个)文件,再在每个文件找出相同的query
近似算法:
因为文件可能大部分都是字符,所以不能用位图处理,即利用布隆过滤器进行比较(布隆过滤器:其实就是一张用来存储字符串hash值的BitMap.)