赞
踩
布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。
布隆过滤器与前面学过的位图很相似,查找效率高且节省空间。但是位图有一个缺点:只能处理整型。布隆过滤器恰好弥补了这一缺陷,可以处理各种类型,最常见的是处理字符串。
位图与布隆过滤器主要区别:
哈希函数:
布隆过滤器有多个哈希函数,这样可以映射多个位置,降低冲突概率。这里参考了3种哈希函数写法:
// BKDR struct HashFuncBKDR { size_t operator()(const string& s) { size_t hash = 0; for (auto ch : s) { hash *= 131; hash += ch; } return hash; } }; // AP struct HashFuncAP { size_t operator()(const string& s) { size_t hash = 0; for (size_t i = 0; i < s.size(); i++) { // 偶数位字符 if ((i & 1) == 0) { hash ^= ((hash << 7) ^ (s[i]) ^ (hash >> 3)); } // 奇数位字符 else { hash ^= (~((hash << 11) ^ (s[i]) ^ (hash >> 5))); } } return hash; } }; // DJB struct HashFuncDJB { size_t operator()(const string& s) { size_t hash = 5381; for (auto ch : s) { hash = hash * 33 ^ ch; } return hash; } };
布隆过滤器的长度与插入的元素个数有关,有人推导了一个公式:
k为哈希函数的个数,这里有3个哈希函数,m为布隆过滤器的长度,n为插入元素的个数,ln2的大小约为0.69,推导出:4.34 * n = m,简化一下m与n的关系为:5n = m
private:
static const size_t M = 5 * N;
bitset<M> _bs;
插入元素时,不同的哈希函数计算出该元素的不同的映射位置,然后将要映射的位置标记为存在,即比特位为1
//插入
void Set(const K& key)
{
size_t hash1 = HashFuncBKDR()(key) % M;
size_t hash2 = HashFuncAP()(key) % M;
size_t hash3 = HashFuncDJB()(key) % M;
_bs.set(hash1);
_bs.set(hash2);
_bs.set(hash3);
}
这里先来对比一下位图与布隆过滤器的查找位置冲突问题:
位图:
布隆过滤器:
代码:
//查找
bool Test(const K& key)
{
size_t hash1 = HashFuncBKDR()(key) % M;
if (!_bs.test(hash1))
return false;
size_t hash2 = HashFuncAP()(key) % M;
if (!_bs.test(hash2))
return false;
size_t hash3 = HashFuncDJB()(key) % M;
if (!_bs.test(hash3))
return false;
}
总结:
布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。 比如:删除图中"百度"元素,如果直接将该元素所对应的二进制比特位置0,“苹果”元素也被删除了,因为这两个元素在多个哈希函数计算出的比特位上刚好有重叠。
一种支持删除的方法:将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。
布隆过滤器:
位图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。