布隆过滤器
面试被问到了海量数据处理相关的问题。然后发现了布隆过滤器这个数据结构,学了一下,结果就是这是acm里面用过的算法。
我把布隆过滤器分解为两个模块,也就是多次哈希+bitset。
多次哈希用来优化时间,bitset优化了空间。
时间复杂度上的原理
我们想想哈希这个算法有什么有什么缺点?当然是哈希冲突。
哈希冲突是无法避免的,所以我们得想个法子降低发生哈希冲突的概率。
我们假设现在有\(n\)种算法某一种哈希算法发生冲突的概率为\(p_i\),那么对于一组数据我们把\(n\)种算法全用上。那发生冲突的概率是多少?所有概率之积,这样的话冲突的概率就大大降低了。
空间复杂度上的优化
布隆过滤器可以高效的检验出某一数据是否在海量数据集合中。而在或者不在是两种状态,我们可以用一个bool数组存一下,C++中的bool是1个字节8位的,这已经很不错了。但是C++提供了更好的容器——bitset。它只需要1位。
这种用法就是网上常说的位图。
衍生:如果我们想要求出现2次的数据怎么办?用两个bitset。10表示出现两次,11表示出现三次及三次以上。
代码
现在这个代码就极为清晰了。
class BloomFilter{
public:
std::bitset<32> bits;
public:
void set(std::string& key){
for(int i = 1;i < 5;i++){
bits[Hash(i,key)] = 1;
}
}
bool isExist(){
bool ok = true;
for(int i = 1;i < 5;i++){
ok &= bits[Hash(i,key)];
}
}
int Hash(int id,std::string key){
if(id == 1){
return Hash1(key);
}
else if(id == 2){
return Hash2(key);
}
else if(id == 3){
return Hash3(key);
}
else if(id == 4){
return Hash4(key);
}else{
return -1;
}
}
int Hash1(std::string& key)
{
int seed = 131;
int hash = 0;
std::string str = key + "key2";
unsigned long count = str.size();
while(count > 0) {
hash = hash * seed + str[str.size() - count];
count--;
}
return (hash & 0x7FFFFFFF) % bits.size();
}
int Hash3(std::string& key)
{
int hash = 0;
std::string str = key + "keykey3";
unsigned long count = str.size();
for (int i = 0; i < count; i++) {
if ((i * 1) == 0) {
hash ^= ((hash << 7) ^ (str[i] ^ hash >> 3));
} else {
hash ^= (~((hash << 11) ^ (str[i]) ^ (hash >> 5)));
}
count--;
}
return (hash & 0x7FFFFFFF) % bits.size();
}
int Hash4(std::string key)
{
int hash = 5381;
std::string str = key + "keykeykey4";
unsigned long count = str.size();
while(count > 0) {
hash += (hash << 5) + (str[str.size() - count]);
count--;
}
return (hash & 0x7FFFFFFF) % bits.size();
}
};
标签:std,count,hash,string,int,布隆,key,过滤器
From: https://www.cnblogs.com/Paranoid5/p/16726783.html