一、定义
如果向之前的章节,40亿个不重复无符号的整形判断是否存在,我们可以选择用位图来解决,那么如果是40亿个邮箱地址我们该如何解决呢。
因此我们便想着能否把邮箱地址按照一定的方式映射到一个集合呢,接着我们只需要看点是否为1就知道这个集合有没有它了,这便是布隆过滤器的基本思想。
我们采用字符串哈希函数来处理字符串,但是一个字符串哈希函数可能会产生很多的冲突,因此我们可以采用多个哈希函数来解决这点。
二、布隆过滤器优缺点
优点
- 相比于其他数据结构,布隆过滤器在存储空间的插入和查询时间都是常数。
- 存在是不确定的,不存在是一定的。
缺点
- 布隆过滤器的缺点在于我们多个字符串可能映射到同一个位,所以随着存入的元素增加,错误率会上升。
- 我们如果要删除这个元素的话就变得很困难,因为一个位可能表示多个元素。但是我们也可以采用引用计数,把每一个位有多少个元素引用记下来,删除的时候只要为的时候就可以删除,这样便可解决删除的问题。
三、代码实现
#include <string>
#include "Bit.h"
using namespace std;
struct _HashFunc1
{
size_t operator()(const string& str)
{
size_t num = 0;
for (int i = 0; i < (int)str.size(); i++)
{
num = num * 131 + str[i];
}
return num;
}
};
struct _HashFunc2
{
size_t operator()(const string& str)
{
size_t num = 0;
for (int i = 0; i < (int)str.size(); i++)
{
num = num * 65599 + str[i];
}
return num;
}
};
struct _HashFunc3
{
size_t operator()(const string& str)
{
size_t magic = 63689;
size_t num = 0;
for (int i = 0; i < (int)str.size(); i++)
{
num = num *magic + str[i];
magic *= 378551;
}
return num;
}
};
template <typename K=string,
class HashFunc1 = _HashFunc1,
class HashFunc2 = _HashFunc2,
class HashFunc3 = _HashFunc3 >
class BloomFilter
{
public:
BloomFilter(size_t range)
: _bm(range)
, _capacity(range)
{}
void Set(const K& key)
{
int index1 = HashFunc1()(key);
int index2 = HashFunc1()(key);
int index3 = HashFunc1()(key);
_bm.Set(index1);
_bm.Set(index2);
_bm.Set(index3);
}
bool Test(const K& key)
{
int index1 = HashFunc1()(key);
int index2 = HashFunc1()(key);
int index3 = HashFunc1()(key);
if (!_bm.Test(index1))
return false;
if (!_bm.Test(index2))
return false;
if (!_bm.Test(index3))
return false;
return true;
}
private:
BitMap _bm;
size_t _capacity;
};