目录
布隆过滤器
布隆过滤器的提出
位图对于map/set这些的最大好处是,位图节省空间,效率高,但是位图也有局限性,它只能处理整数。那么当我们不想处理整数了,又想节省空间,这种方案就是布隆过滤器。布隆过滤器的特点还是节省空间,它可以处理自定义类型。
布隆过滤器的概念
布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的 一种紧凑型的、比较巧妙的概率型数据结 构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函 数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。
比如说有“sort”,"left","right"着三个单词,有没有一种方法将这三个单词不用存储的方法,用最节省空间的方法来标记它们呢?可以将字符串转换成一个对应的整数,跟哈希表的方法一样。
假设这三个字符串转换成20,30,45。当遇到sort,它对应的是20,去找它在不在,在就是1,不在就是0。
用这种方法,比起红黑树这种有附带消耗的,非常节省空间。但是这种方案同样存在一个问题,相比于位图,位图是直接定址法,我们可以在可控范围内开辟空间并进行定位。但是字符串这种,比如说10个由小写字母构成的字符串,有26^10种可能性。这只是小写字母,还有大写字母,特殊符号,数字等等这些。字符串的数量非常大,如果不限定长度,字符串是无限的,整数是有限的。这样也就造成不同的字符串可能对应同一个数字,就会误判,本来还没有出现过的字符串,由于跟别的字符串使用同一个整数,而那个整数出现过,造成了误判。
而这个误判:当字符串在的时候会误判,也就是说,假设abb和abaa这两个字符串映射同一个整数,abb出现过了,abaa没有出现过,会误判abaa也存在。而abb和abaa两个都不在的时候,不会造成误判,二者对应的整数都是0。而位图没有误判,因为位图没有哈希冲突,每个值一定有唯一的位置,因为它处理的是整数,如果所有的整数都在,也就42亿多。但是字符串太多一定存在冲突。
- 在。存在误判
- 不在,准确的
我们想到了这个问题,布隆也会想到这个问题。布隆也允许哈希冲突,一个整数对应好几个字符串,但是需要降低误判率,那么如何降低误判率?当映射一个位置容易冲突,那么我们映射多个位置,假设一个字符串影射了三个位置。
sort映射了三个位置,有一个位置和right冲突了,但是没关系。这时候每个值都映射三个位置,现在要冲突没那么容易,一个位置容易冲突,但是三个位置不容易冲突,即便三个位置也冲突,那么可以设置一个字符串映射八个位置。这样误判率就被降低了。
但是这里映射的位置也不能太多,映射的多,占的空间也多,找的次数也多,我们使用位图这样的方式就是为了提高效率并且节省空间。映射的多了也就没那么节省空间了。
布隆过滤器的实现
插入
这里用了模板class K,并给了默认值string,因为布隆过滤器最常见的是string类型。默认情况下是给string类型用的,这里也可以变成自定义类型,如果有Person类这样的,我们从中提取唯一信息,如身份证号,这样的能转成唯一数字的方式。
还要给一个非类型模板参数N,因为给布隆开比特位。我们的字符串要映射三个比特的位置,所以要写三个仿函数方法:HashFunc1,HashFunc2,HashFunc3。因为模板参数的缺省值要从右往左缺省,所以class K=string要写在后面。
对于字符串转整形的哈希函数有很多,具体的实现可以参考这篇文章:
其中里面对哈希的各种算法效率做了排序,其中排列前3的算法分别是:BKDRHash,APHash,DJBHash。所以我们使用这几种算法就可以将同一个字符串转换成不同的整数值。
struct BKDRHash
{
size_t operator()(const string& s)
{
size_t value = 0;
for (auto ch : s)
{
value *= 31;
value += ch;
}
return value;
}
};
struct APHash
{
size_t operator()(const string& s)
{
size_t hash = 0;
for (long i = 0; i < s.size(); i++)