布隆过滤器

布隆过滤器

面试被问到了海量数据处理相关的问题。然后发现了布隆过滤器这个数据结构,学了一下,结果就是这是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();
    }
};
posted @ 2022-09-24 21:58  Paranoid5  阅读(34)  评论(0编辑  收藏  举报