布隆过滤器
布隆过滤器就是为了解决位图不能解决的问题。
- 用哈希表存储用户记录,缺点:浪费空间
- 用位图存储用户记录,缺点:不能处理哈希冲突
- 将哈希与位图结合,即布隆过滤器
布隆过滤器的概念
布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结
构,特点是高效地插入和查询,可以用来告诉* “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间
为了降低冲突的概率,我们可以把一个值映射到三个位置上去。
布隆过滤器的插入
先构造出三种不同的哈希函数:
struct HashBKDR { // BKDR size_t operator()(const string& key) { size_t val = 0; for (auto ch : key) { val *= 131; val += ch; } return val; } }; struct HashAP { // BKDR size_t operator()(const string& key) { size_t hash = 0; for (size_t i = 0; i < key.size(); i++) { if ((i & 1) == 0) { hash ^= ((hash << 7) ^ key[i] ^ (hash >> 3)); } else { hash ^= (~((hash << 11) ^ key[i] ^ (hash >> 5))); } } return hash; } }; struct HashDJB { // BKDR size_t operator()(const string& key) { size_t hash = 5381; for (auto ch : key) { hash += (hash << 5) + ch; } return hash; } };
布隆过滤器当中,如果没有找到这个值,那么就不存在,如果找到了这个值,却不一定存在,因为存在哈希冲突。
所以在判断一个值在不在的时候就得去判断这个值是不是不在这个位图当中。
void Set(const K& key) { Hash1 h1; Hash2 h2; Hash3 h3; //size_t hash1 = Hash1()(key) % (_ratio*N); //这样也可以,先创建一个Hash1()匿名对象,然后调用operator() size_t hash1 = h1(key) % (_ratio * N); _bits.set(hash1); size_t hash2 = h2(key) % (_ratio * N); _bits.set(hash2); size_t hash3 = h3(key) % (_ratio * N); _bits.set(hash3); }
bool Test(const K& key) { Hash1 h1; Hash2 h2; Hash3 h3; size_t hash1 = h1(key) % (_ratio * N); if (!_bits.test(hash1)) { return false; } size_t hash2 = h2(key) % (_ratio * N); if (!_bits.test(hash2)) { return false; } size_t hash3 = h3(key) % (_ratio * N); if (!_bits.test(hash3)) { return false; } return true; }
布隆过滤器的删除
其实删除要实现的话意义不大,如果实现了删除,布隆过滤器原本的优势就没有了,还不如用哈希表呢
对每一个位置进行一个数量的标记即可。