布隆过滤器实现(哈希+位图)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hansionz/article/details/82591882

布隆过滤器(bloomfiliter)

布隆过滤器是哈希和位图的变形,它的基本思想是:通过一个Hash函数将一个元素映射成一个位矩阵中的一个点,我们只需查看这个位置是1还是0就知道集合中是否存在它。但是由于哈希冲突的原因,即不同的元素经过散列函数后可能产生相同的哈希地址,我们很可能导致误判。为了降低误判的概率,我们将一个元素经过多个散列函数映射到多个位上,如果这几个位都为1,我们认为它是存在的;如果有一位为0,我们认为它不存在。

为什么会在位图的基础上产生布隆过滤器呢?

对于数字的话,位图是可以处理的,因为他们是不存在冲突的,每一个数字对于一个唯一的哈希地址;但是对于字符串,位图是没有办法处理的,因为字符串存在哈希冲突。因此,我们只能通过我们将一个元素经过多个散列函数映射到多个位上来降低误判的概率,布隆过滤器正是基于这个特点应用而生的。

位图的实现方法单独实现在我的另一篇博客:
https://blog.csdn.net/hansionz/article/details/82585228
注意:

  • 对于布隆过滤器来说,所得出来的结果是不一定准确的,存在不一定存在,但不存在一定不存在。(存在是准确的,不存在是不准确的)
  • 布隆过滤器不存在将要放置的内容映射的地址设置为0(既删除),因为一个位置可能对于多个字符串映射的地址,删除了一个会影响另一个

对于字符串HashFunc的实现方法建议去看另一篇博客:
http://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html

一.第一种实现方法

直接在结构体中封装一个位图,然后在设置的时候多次调用BloomFunc函数计算哈希地址。

0.定义结构
//布隆过滤器
typedef struct BloomFilter
{
    BitSet bs;//封装一个位图
}BloomFilter;
1.函数实现
//初始化布隆过滤器
void BloomFilterInit(BloomFilter* pbf)
{
    assert(pbf);

    BitSetInit(&pbf->bs, MAXSIZE);
}
//销毁布隆过滤器(释放空间)
void BloomFilterDestroy(BloomFilter* pbf)
{
    assert(pbf);

    BitSetDestory(&pbf->bs);
}
//将要放置的内容映射的地址设置为1
void BloomFilterSet(BloomFilter* pbf, const char* str)
{
    assert(pbf&&str);
    //1.根据哈希函数计算哈希地址(将字符串转换为整数)
    size_t index1 = HashFunc1(str);
    size_t index2 = HashFunc2(str);
    size_t index3 = HashFunc3(str);
    //2.把哈希地址映射在位图的位置设置为1
    BitSetSet(&pbf->bs, index1);
    BitSetSet(&pbf->bs, index2);
    BitSetSet(&pbf->bs, index3);
}
//判断一个字符串是否存在(存在返回1,不存在返回0)
int BloomFilterTest(BloomFilter* pbf, const char* str)
{
    assert(pbf&&str);
    //3个函数对于的地址都为1才能说明字符串存在,否则不存在
    int index1 = HashFunc1(str);
    if (BitSetTest(&pbf->bs, index1) == 0)
        return 0;
    int index2 = HashFunc2(str);
    if (BitSetTest(&pbf->bs, index2) == 0)
        return 0;
    int index3 = HashFunc3(str);
    if (BitSetTest(&pbf->bs, index3) == 0)
        return 0;
    return 1;
}
二.第二种方法

将一个函数指针数组和一个位图分装在一个结构体中,这样在设置数据的时候,就不要多次调用HashFunc1HashFunc2等函数了,直接根据函数指针数组去调用,方便一些。

0.定义结构
#define MAXSIZE 10000//最大容量
#define FUNCMAXSIZE 3//哈希函数最多个数
//函数指针类型重命名
typedef size_t (*BloomFunc)(const char* str);

typedef struct BloomFilter_op
{
    BitSet bs;//位图
    BloomFunc bloomfunc[FUNCMAXSIZE];//函数指针数组
}BloomFilter_op;
1.函数实现
//初始化布隆过滤器
void BloomFilterInit_op(BloomFilter_op* pbf, BloomFunc fun1, BloomFunc fun2, BloomFunc fun3)
{
    assert(pbf);
    if (fun1 == NULL || fun2 == NULL || fun3 == NULL)
        return;
    BitSetInit(&pbf->bs, MAXSIZE);
    //初始化函数指针数组
    pbf->bloomfunc[0] = fun1;
    pbf->bloomfunc[1] = fun2;
    pbf->bloomfunc[2] = fun3;
}
//销毁布隆过滤器(释放空间)
void BloomFilterDestroy_op(BloomFilter_op* pbf)
{
    assert(pbf);
    //销毁位图
    BitSetDestory(&pbf->bs);
    //将函数指针数组中的每一个元素都设置为NULL
    memset(pbf->bloomfunc, NULL, sizeof(BloomFunc)*FUNCMAXSIZE);
}
//将要放置的内容映射的地址设置为1
void BloomFilterSet_op(BloomFilter_op* pbf, const char* str)
{
    assert(pbf);
    //定义数组存放多个哈希地址
    size_t bloomindex[FUNCMAXSIZE];
    int i = 0;
    //1.计算每个哈希地址放在数组中
    for (; i < FUNCMAXSIZE; i++)
    {
        bloomindex[i] = pbf->bloomfunc[i](str);
    }
    //2.找到哈希地址对于在位图中的位置,并把那个位设置为1
    for (i = 0; i < FUNCMAXSIZE; i++)
    {
        BitSetSet(&pbf->bs, bloomindex[i]);
    }
}
//判断一个字符串是否存在(存在返回1,不存在返回0)
int BloomFilterTest_op(BloomFilter_op* pbf, const char* str)
{
    assert(pbf);
    size_t bloomindex[FUNCMAXSIZE];
    int i = 0;
    //1.计算每个哈希地址放在数组中
    for (; i < FUNCMAXSIZE; i++)
    {
        bloomindex[i] = pbf->bloomfunc[i](str);
    }
    //2.如果3个位置都为1,则存在,否则不存在
    for (i = 0; i < FUNCMAXSIZE; i++)
    {
        if (BitSetTest(&pbf->bs, bloomindex[i]) == 0)
            return 0;
    }
    return 1;
}

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/82591882