赞
踩
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
基本概念 : 如果想要判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表,树等等数据结构都是这种思路. 但是随着集合中元素的增加,我们需要的存储空间越来越大,检索速度也越来越慢(O(n),O(logn))。不过世界上还有一种叫作散列表(又叫哈希表,Hashtable)的数据结构。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bitarray)中的一个点。这样一来,我们只要看看这个点是不是1就可以知道集合中有没有它了。这就是布隆过滤器的基本思想。
Hash面临的问题就是冲突。假设Hash函数是良好的,如果我们的位阵列长度为m个点,那么如果我们想将冲突率降低到例如 1%, 这个散列表就只能容纳m / 100个元素。显然这就不叫空间效率了(Space-efficient)了。解决方法也简单,就是使用多个Hash,如果它们有一个说元素不在集合中,那肯定就不在。如果它们都说在,虽然也有一定可能性它们在说谎,不过直觉上判断这种事情的概率是比较低的。
布隆过滤器的优点 :
布隆过滤器的缺点 :
如下图所示 : 布隆过滤器是一个元素映射多个位置 ;
布隆过滤器的实现也是需要依靠位图为底层来实现
位图的实现详解 ( 传送门 ) -- https://blog.csdn.net/ds19980228/article/details/82592294
BloomFilter . c
- #include "BitMap.h"
- //元素第一个映射的位置
- size_t BLFHashFun1(BitMap * blf, char* x)
- {
- assert(blf);
- size_t ret = 0;
- while (*x){
- //31作为乘子
- ret += ret * 31 + *x;
- x++;
- }
- //取模,计算位置
- return ret%blf->capacity;
- }
- //元素第二个映射的位置
- size_t BLFHashFun2(BitMap * blf, char* x)
- {
- assert(blf);
- size_t ret = 0;
- while (*x){
- //131作为乘子
- ret += ret * 131 + *x;
- x++;
- }
- //取模,计算位置
- return ret%blf->capacity;
- }
- //元素第三个映射的位置
- size_t BLFHashFun3(BitMap * blf, char* x)
- {
- assert(blf);
- size_t ret = 0;
- while (*x){
- //51作为乘子
- ret += ret * 51 + *x;
- x++;
- }
- //取模,计算位置
- return ret%blf->capacity;
- }
- //布隆过滤器初始化
- void BLFInit(BitMap * blf, size_t capacity)
- {
- assert(blf);
- //要映射三个位置,为了降低误算率,容量开辟原来的三倍
- BMPInit(blf, capacity * 3);
- }
- //布隆过滤器销毁
- void BLFDestory(BitMap * blf)
- {
- assert(blf);
- BMPDestory(blf);
- }
- //布隆过滤器存储
- void BLFInsert(BitMap * blf, char* x)
- {
- //将要映射的三个位置找出然后分别存储
- assert(blf);
- int index1 = BLFHashFun1(blf, x);
- int index2 = BLFHashFun2(blf, x);
- int index3 = BLFHashFun3(blf, x);
- BMPInsert(blf, index1);
- BMPInsert(blf, index2);
- BMPInsert(blf, index3);
- }
- //由于布隆过滤器中元素的映射是互相影响的,所以不能直接删除
- //某一个元素的映射
- //void BLFResert(BLF * blf, size_t x);
- //检查元素是否存在
- //这里要判断一个元素是否存在,它映射的三个为必须均为1
- //这要有一位不满足条件,则元素不存在
- //这里如果判断出一个元素存在,结果是不准确定的,而当一个
- //元素被判断不存在时,结果一定是准确的
- int BLFCheck(BitMap * blf, char* x)
- {
- assert(blf);
- //检查第一个映射位
- int index1 = BLFHashFun1(blf, x);
- if (!BMPCheck(blf, index1))
- return 0;
- //检查第二个映射位
- int index2 = BLFHashFun2(blf, x);
- if (!BMPCheck(blf, index2))
- return 0;
- //检查第三个映射位
- int index3 = BLFHashFun3(blf, x);
- if (!BMPCheck(blf, index3))
- return 0;
- printf("字符串映射的三个位置分别为 : %d %d %d \n", index1, index2, index3);
- return 1;
- }
- //测试
- //如果存在返回1,不存在返回0
- void BLFTest()
- {
- BitMap blf;
- BLFInit(&blf, 50);
- BLFInsert(&blf, "abc");
- BLFInsert(&blf, "sdghjddh k");
- BLFInsert(&blf, "https://blog.csdn.net/ds19980 228");
- printf("%d\n", BLFCheck(&blf, "abc"));
- printf("%d\n", BLFCheck(&blf, "acb"));
- printf("%d\n", BLFCheck(&blf, "sdghjddh k"));
- printf("%d\n", BLFCheck(&blf, "sdghjddhk "));
- printf("%d\n", BLFCheck(&blf, "https://blog.csdn.net/ds1998 0228"));
- printf("%d\n", BLFCheck(&blf, "https://blog.csdn.net/ds199802 28"));
- BLFDestory(&blf);
- }
这里的 BloomFilter . h 的头文件就是 BitMap . h 的头文件
- #pragma once
-
- #include <string.h>
- #include <stdio.h>
- #include <assert.h>
- #include <stdlib.h>
-
- //数据结构
- typedef struct BitMap
- {
- char * data;
- //位图最大能表示的比特位数
- size_t capacity;
- }BitMap;
-
- //位图的初始化
- void BMPInit(BitMap * bmp, size_t capacity);
- //位图的销毁
- void BMPDestory(BitMap * bmp);
- //位图的存储
- void BMPInsert(BitMap * bmp, size_t x);
- //位图的删除
- void BMPResert(BitMap * bmp, size_t x);
- //检查元素是否存在
- int BMPCheck(BitMap * bmp, size_t x);
- //测试
- void BMPTest();
-
- //布隆过滤器初始化
- void BLFInit(BitMap * bmp, size_t capacity);
- //布隆过滤器销毁
- void BLFDestory(BitMap * bmp);
- //布隆过滤器存储
- void BLFInsert(BitMap * bmp, char* x);
- //void BLFResert(BitMap * bmp, char x);
- //检查元素是否存在
- int BLFCheck(BitMap * bmp, char* x);
- //测试
- void BLFTest();
Test . c 文件
- #include "BitMap.h"
- int main()
- {
- BLFTest();
- system("pause");
- return 0;
- }
调试结果如下 : 在原来字符串的基础上做一些微小的变化来测试
若有出错或不懂的地方, 欢迎留言, 共同进步 !
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。