如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间越来越大。同时检索速度也越来越慢。
Bloom Filter 是一种空间效率很高的随机数据结构,Bloom filter 可以看做是对 bit-map 的扩展, 它的原理是:
`>**布隆过滤器只是位图的一个扩展。位图是一个位表示key的存在状态,而布隆过滤器是多个位表示表示一个数的存在状态**
注意:对于布隆过滤器查找一个数据
1.找到不一定存在。
2.找不到一定不存在。
这说明布隆过滤器是近似查找。
`
``
[这里有关布隆过滤器更详细的介绍,讲的很清楚:https://segmentfault.com/a/1190000002729689
下面是代码实现:
/* [布隆过滤器的头文件:位图] :
http://blog.csdn.net/uagvdu/article/details/53124166
#pragma once
#include<iostream>
#includiostream>
#include"bitMap.h"
using namespace std;
template<class K>
struct _func1
{
size_t operator()(const K& key)
{
return key;
}
};
template<class K>
struct _func2
{
size_t operator()(const K& key)
{
return key;
}
};
template<class K>
struct _func3
{
size_t operator()(const K& key)
{
return key;
}
};
template<class K>
struct _func4
{
size_t operator()(const K& key)
{
return key;
}
};
template<class K>
struct _func5
{
size_t operator()(const K& key)
{
return key;
}
};
template<> //模板的特化:必须要先写一个同名的模板类或者结构体
struct _func1<string>
{
size_t JSHash(const char *str)
{
if (!*str) // 这是由本人添加,以保证空字符串返回哈希值0
return 0;
register size_t hash = 1315423911;
while (size_t ch = (size_t)*str++)
{
hash ^= ((hash << 5) + ch + (hash >> 2));
}
return hash;
}
size_t operator() (const string& str)
{
return JSHash(str.c_str());
}
};
template<>
struct _func2<string>
{
size_t APHash(const char *str)
{
register size_t hash = 0;
size_t ch;
for (long i = 0; ch = (size_t)*str++; i++)
{
if ((i & 1) == 0)
{
hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
}
else
{
hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
}
}
return hash;
}
size_t operator() (const string& str)
{
return APHash(str.c_str());
}
};
template<>
struct _func3<string>
{
size_t RSHash(const char *str)
{
register size_t hash = 0;
size_t magic = 63689;
while (size_t ch = (size_t)*str++)
{
hash = hash * magic + ch;
magic *= 378551;
}
return hash;
}
size_t operator() (const string& str)
{
return RSHash(str.c_str());
}
};
template<>
struct _func4<string>
{
size_t SDBMHash(const char *str)
{
register size_t hash = 0;
while (size_t ch = (size_t)*str++)
{
hash = 65599 * hash + ch;
//hash = (size_t)ch + (hash << 6) + (hash << 16) - hash;
}
return hash;
}
size_t operator() (const string& str)
{
return SDBMHash(str.c_str());
}
};
template<>
struct _func5<string>
{
size_t BKDRHash(const char *str)
{
register size_t hash = 0;
while (size_t ch = (size_t)*str++)
{
hash = hash * 131 + ch;
// 也可以乘以31、131、1313、13131、131313..
}
return hash;
}
size_t operator() (const string& str)
{
return BKDRHash(str.c_str());
}
};
template < class K = string,
class func1 = _func1<K>,
class func2 = _func2<K>,
class func4 = _func4<K>,
class func5 = _func5<K >> /*五种计算string类型转换为数字的结构体,内部用
的是仿函数,重载operator()()。*/
class BloomFilter
{
public:
//num表示数据的范围,而不是数据的个数,只要在该范围内都可以被位图或者bloom表示
// _range布隆过滤器的范围:
插入一个字符串的时候,对于不知道key大小的字符串来说,当key有可能非常大的时候,如果按照位图那样直接定址法,传参过去,难道我也开辟一个非常大的顺序表?所以此处采用除留余数法,让字符串始终落在所开辟的空间内部,不至于过多的浪费空间
//没用到位的时候,别想位,range只是num这个关键字表示的范围 range个字节,key%range 得到key所在的位置 ,此时这个位置并不是位,
因为你还没有传参到位图中
BloomFilter(size_t num)
:_bm(num*5)
, _range(num*5)
{
}
void Set(const K& key) //用相同的key调用不同的函数得到不同的位,设置为1
{
//key % range;
_bm.Set(func1()(key) % _range);
_bm.Set(func2()(key) % _range); //类似于哈希表的除留余数法
_bm.Set(func3()(key) % _range); // 并且顺序表永远不会越界
_bm.Set(func4()(key) % _range);
_bm.Set(func5()(key) % _range);
}
bool Test(const K& key)
{
return (_bm.Test(func1()(key) % _range)
&& _bm.Test(func2()(key) % _range)
&& _bm.Test(func3()(key) % _range)
&& _bm.Test(func4()(key) % _range)
&& _bm.Test(func5()(key) % _range));
}
protected:
BitMap _bm;
size_t _range;
};
void TestBloomFilter()
{
char* url1 = "file:///C:/Users/xjh/AppData/Local/Temp/360zip$Temp/360$2/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95/%E5%90%84%E7%A7%8D%E5%AD%97%E7%AC%A6%E4%B8%B2Hash%E5%87%BD%E6%95%B0%20-%20clq%20-%20%E5%8D%9A%E5%AE%A2%E5%9B%AD.html";
char* url2 = "file:///C:/Users/xjh/AppData/Local/Temp/360zip$Temp/360$2/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95/%E5%90%84%E7%A7%8D%E5%AD%97%E7%AC%A6%E4%B8%B2Hash%E5%87%BD%E6%95%B0%20-%20clq%20-%20%E5%8D%9A%E5%AE%A2%E5%9B%AE.html";
char* url3 = "file:///C:/Users/xjh/AppData/Local/Temp/360zip$Temp/360$2/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95/%E5%90%84%E7%A7%8D%E5%AD%97%E7%AC%A6%E4%B8%B2Hash%E5%87%BD%E6%95%B0%20-%20clq%20-%20%E5%8D%9A%E5%AE%A2%E5%9B%AF.html";
char* url4 = "file:///C:/Users/xjh/AppData/Local/Temp/360zip$Temp/360$2/%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%93%88%E5%B8%8C%E7%AE%97%E6%B3%95/%E5%90%84%E7%A7%8D%E5%AD%97%E7%AC%A6%E4%B8%B2Hash%E5%87%BD%E6%95%B0%20-%20clq%20-%20%E5%8D%9A%E5%AE%A2%E5%9B%AG.html";
BloomFilter<> bf2(5);
bf2<et(url1);
bf2.Set(url2);
bf2.Set(url3);
cout << "Test?" << bf2.Test(url1) << endl;
cout << "Test?" << bf2.Test(url2) << endl;
cout << "Test?" << bf2.Test(url3) << endl;
cout << "Test?" << bf2.Test(url4) << endl;
cout << "----------------- "<< endl;
BloomFilter<int> bf(150);
for (int i = 70; i <142; i++)
{
bf.Set(i);
}
cout << bf.Test(75) << endl;
cout << bf.Test(71) << endl;
cout << bf.Test(5) << endl;
cout << bf.Test(555) << endl;
ut << bm.Test(71) << endl;
cout << bm.Test(5) << endl;
}
布隆过滤器
最新推荐文章于 2024-04-20 20:55:36 发布