相关概念知识
概念:布隆过滤器是一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。
实质:将哈希与位图结合,即布隆过滤器。
布隆过滤器优点
- 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数),与数据量大小无关
- 哈希函数相互之间没有关系,方便硬件并行运算
- 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
布隆过滤器缺陷
- 有误判率,即不能准确判断元素是否在集合中
- 不能获取元素本身
- 一般情况下不能从布隆过滤器中删除元素
具体操作
插入:将要插入的数据经过K个哈希函数计算后,将位图里这些对应的哈希值的位置逐个置为1,也就是会有K个位置被置为1。
查找:将要查找的数据经过K个哈希函数计算后,去位图里的对应的哈希值的位置逐个查找,如果有其中一个是0,则肯定不存在,如果全是1,则大概率存在(因为某些1可能是其他数据置的1)。所以哈希函数越多,查找的准确率越高
删除:因为删除可能会删掉其他数据的1,从而导致数据错误,所以布隆过滤器是没有删除操作的
源码
布隆过滤器要用到的位图
class BitMap
{
private:
vector<int> _table;
public:
BitMap(size_t range)
{
//>>5是因为:一个字节32位,>>5相当于除以32。+1是因为:如果不是32的倍数,多出来的也要计算,例如33/32 =1,实际应该要2个字节来算
_table.resize((range >> 5) + 1);
}
void set(int data)
{
//算出数组的下标
size_t int_index = data >> 5;
//算出一个字节里的比特位位置
size_t bit_index = (data % 32);
//或上1,就表示有这个数了
_table[int_index] |= (1 << bit_index);
}
bool find(int data)
{
//算出数组的下标
size_t int_index = data >> 5;
//算出一个字节里的比特位位置
size_t bit_index = (data % 32);
//看那一比特位是否是1
return ((_table[int_index] >> bit_index) & 1);
}
void reset(int data)
{
//算出数组的下标
size_t int_index = data >> 5;
//算出一个字节里的比特位位置
size_t bit_index = (data % 32);
//将那一位与0,其他位这时是与的1(但是与1对其他位没影响)
_table[int_index] &= ~(1 << bit_index);
}
};
哈希函数(这里只写了三个,可以再增加)
struct Hfun1
{
size_t operator()(const string& str)
{
size_t hash = 0;
for (const auto& ch : str)
{
hash = hash * 131 + ch;
}
return hash;
}
};
struct Hfun2
{
size_t operator()(const string& str)
{
size_t hash = 0;
for (const auto& ch : str)
{
hash = hash * 65599 + ch;
}
return hash;
}
};
struct Hfun3
{
size_t operator()(const string& str)
{
size_t magic = 0;
size_t hash = 0;
for (const auto& ch : str)
{
hash = hash * magic + ch;
magic *= 378551;
}
return hash;
}
};
布隆过滤器
template<class K,class Hfun1,class Hfun2,class Hfun3>
class BloomFilter
{
private:
BitMap _bm;
size_t _bit_num;
public:
BloomFilter(size_t range)
:_bm(range * 5)//因为是多个映射,所以冲突的概率大,所以要多开一些
, _bit_num(range * 5)
{ }
void set(const K& key)
{
//计算出各个哈希函数的位置
size_t index1 = Hfun1()(key) % _bit_num;
size_t index2 = Hfun2()(key) % _bit_num;
size_t index3 = Hfun3()(key) % _bit_num;
//插入到对应的位图位置
_bm.set(index1);
_bm.set(index2);
_bm.set(index3);
}
bool test(const K& key)
{
//计算出各个哈希函数的位置
size_t index1 = Hfun1()(key) % _bit_num;
size_t index2 = Hfun2()(key) % _bit_num;
size_t index3 = Hfun3()(key) % _bit_num;
//逐个检查每个对应比特位是否是1,是1则可能存在,是0则肯定不存在
if (_bm.find(index1) == false)
{
return false;
}
if (_bm.find(index2) == false)
{
return false;
}
if (_bm.find(index3) == false)
{
return false;
}
//虽然返回true了,但是也只是有可能存在,因为有些位图的1可能是其他的数据映射的
return true;
}
};