首页 > 程序开发 > 软件开发 > 其他 >

布隆过滤器

2016-11-11

如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间越来越大。同时检索速度也越来越慢。

如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间越来越大。同时检索速度也越来越慢。

Bloom Filter 是一种空间效率很高的随机数据结构,Bloom filter 可以看做是对 bit-map 的扩展, 它的原理是:

布隆过滤器只是位图的一个扩展。位图是一个位表示key的存在状态,而布隆过滤器是多个位表示表示一个数的存在状态

注意:对于布隆过滤器查找一个数据

1.找到不一定存在。

2.找不到一定不存在。

这说明布隆过滤器是近似查找。

下面是代码实现:

/* [布隆过滤器的头文件:位图]    :
https://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;
}
相关文章
最新文章
热点推荐