bloom filter概念讲解以及代码分析_C 语言

一. 简介
1.什么是bloom filter?
Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员,这种检测只会对在集合内的数据错判,而不会对不是集合内的数据进行错判,这样每个检测请求返回有“在集合内(可能错误)”和“不在集合内(绝对不在集合内)”两种情况,可见 Bloom filter 是牺牲了正确率换取时间和空间。

2.bloom filter的计算方法?
如需要判断一个元素是不是在一个集合中,我们通常做法是把所有元素保存下来,然后通过比较知道它是不是在集合内,链表、树都是基于这种思路,当集合内元素个数的变大,我们需要的空间和时间都线性变大,检索速度也越来越慢。 Bloom filter 采用的是哈希函数的方法,将一个元素映射到一个 m 长度的阵列上的一个点,当这个点是 1 时,那么这个元素在集合内,反之则不在集合内。这个方法的缺点就是当检测的元素很多的时候可能有冲突,解决方法就是使用 k 个哈希 函数对应 k 个点,如果所有点都是 1 的话,那么元素在集合内,如果有 0 的话,元素则不在集合内。

3.bloom filter的特点?
Bloom filter 优点就是它的插入和查询时间都是常数,另外它查询元素却不保存元素本身,具有良好的安全性。它的缺点也是显而易见的,当插入的元素越多,错判“在集合内”的概率就越大了,另外 Bloom filter 也不能删除一个元素,因为多个元素哈希的结果可能在 Bloom filter 结构中占用的是同一个位,如果删除了一个比特位,可能会影响多个元素的检测。

二. 代码实现
现下面在linux下实现了bloom filter的功能代码:

复制代码 代码如下:

// bloom.h:
#ifndef __BLOOM_H__
#define __BLOOM_H__

#include<stdlib.h>

typedef unsigned int (*hashfunc_t)(const char *);
typedef struct {
size_t asize;
unsigned char *a;
size_t nfuncs;
hashfunc_t *funcs;
} BLOOM;

BLOOM *bloom_create(size_t size, size_t nfuncs, ...);
int bloom_destroy(BLOOM *bloom);
int bloom_add(BLOOM *bloom, const char *s);
int bloom_check(BLOOM *bloom, const char *s);

#endif

// bloom.c:
#include<limits.h>
#include<stdarg.h>

#include"bloom.h"

#define SETBIT(a, n) (a[n/CHAR_BIT] |= (1<<(n%CHAR_BIT)))
#define GETBIT(a, n) (a[n/CHAR_BIT] & (1<<(n%CHAR_BIT)))

BLOOM *bloom_create(size_t size, size_t nfuncs, ...)
{
BLOOM *bloom;
va_list l;
int n;

if(!(bloom=malloc(sizeof(BLOOM)))) return NULL;
if(!(bloom->a=calloc((size+CHAR_BIT-1)/CHAR_BIT, sizeof(char)))) {
free(bloom);
return NULL;
}
if(!(bloom->funcs=(hashfunc_t*)malloc(nfuncs*sizeof(hashfunc_t)))) {
free(bloom->a);
free(bloom);
return NULL;
}

va_start(l, nfuncs);
for(n=0; n<nfuncs; ++n) {
bloom->funcs[n]=va_arg(l, hashfunc_t);
}
va_end(l);

bloom->nfuncs=nfuncs;
bloom->asize=size;

return bloom;
}

int bloom_destroy(BLOOM *bloom)
{
free(bloom->a);
free(bloom->funcs);
free(bloom);

return 0;
}

int bloom_add(BLOOM *bloom, const char *s)
{
size_t n;

for(n=0; n<bloom->nfuncs; ++n) {
SETBIT(bloom->a, bloom->funcs[n](s)%bloom->asize);
}

return 0;
}

int bloom_check(BLOOM *bloom, const char *s)
{
size_t n;

for(n=0; n<bloom->nfuncs; ++n) {
if(!(GETBIT(bloom->a, bloom->funcs[n](s)%bloom->asize))) return 0;
}

return 1;
}  

// test.c:
#include<stdio.h>
#include<string.h>

#include"bloom.h"
//下面为两种哈希算法函数
unsigned int sax_hash(const char *key)
{
unsigned int h=0;

while(*key) h^=(h<<5)+(h>>2)+(unsigned char)*key++;

return h;
}

unsigned int sdbm_hash(const char *key)
{
unsigned int h=0;
while(*key) h=(unsigned char)*key++ + (h<<6) + (h<<16) - h;
return h;
}

int main(int argc, char *argv[])
{
FILE *fp;
char line[1024];
char *p;
BLOOM *bloom;

if(argc<2) {
fprintf(stderr, "ERROR: No word file specified\n");
return EXIT_FAILURE;
}

if(!(bloom=bloom_create(2500000, 2, sax_hash, sdbm_hash))) {
fprintf(stderr, "ERROR: Could not create bloom filter\n");
return EXIT_FAILURE;
}

if(!(fp=fopen(argv[1], "r"))) {
fprintf(stderr, "ERROR: Could not open file %s\n", argv[1]);
return EXIT_FAILURE;
}

while(fgets(line, 1024, fp)) {
if((p=strchr(line, '\r'))) *p='\0';//回车
if((p=strchr(line, '\n'))) *p='\0';//换行

bloom_add(bloom, line);
}

fclose(fp);

while(fgets(line, 1024, stdin)) {
if((p=strchr(line, '\r'))) *p='\0';
if((p=strchr(line, '\n'))) *p='\0';

p=strtok(line, " \t,.;:\r\n?!-/()");
while(p) {
if(!bloom_check(bloom, p)) {
printf("No match for ford \"%s\"\n", p);
}
                    else
                      printf("match for ford \"%s\"\n",p);
p=strtok(NULL, " \t,.;:\r\n?!-/()");
}
}

bloom_destroy(bloom);

return EXIT_SUCCESS;
}  

// Makefile:
   all: bloom

bloom: bloom.o test.o
           cc -o bloom -Wall -pedantic bloom.o test.o

bloom.o: bloom.c bloom.h
           cc -o bloom.o -Wall -pedantic -ansi -c bloom.c

test.o: test.c bloom.h
           cc -o test.o -Wall -pedantic -ansi -c test.c

时间: 2024-10-24 08:58:58

bloom filter概念讲解以及代码分析_C 语言的相关文章

爬虫技术之bloom filter(含java代码)

在爬虫系统中,在内存中维护着两个关于URL的队列,ToDo队列和Visited队列,ToDo队列存放的是 爬虫从已经爬取的网页中解析出来的即将爬取的URL,但是网页是互联的,很可能解析出来的URL是已经 爬取到的,因此需要VIsited队列来存放已经爬取过的URL.当爬虫从ToDo队列中取出一个URL的时候, 先和Visited队列中的URL进行对比,确认此URL没有被爬取后就可以下载分析来.否则舍弃此URL,从 Todo队列取出下一个URL继续工作. 然后,我们知道爬虫在爬取网页时,网页的量是

解析bitmap处理海量数据及其实现方法分析_C 语言

[什么是Bit-map] 所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省. 如果说了这么多还没明白什么是Bit-map,那么我们来看一个具体的例子,假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复).那么我们就可以采用Bit-map的方法来达到排序的目的.要表示8个数,我们就只需要8个Bit(1Bytes),首先我们开辟1Byte的空间,将这些空间的所

C语言实现的猜拳游戏代码分享_C 语言

这是一个简单的猜拳游戏(剪子包子锤),让你与电脑对决.你出的拳头由你自己决定,电脑则随机出拳,最后判断胜负. 下面的代码会实现一个猜拳游戏,让你与电脑对决.你出的拳头由你自己决定,电脑则随机出拳,最后判断胜负. 启动程序后,让用户出拳,截图: 用户出拳,显示对决结果:截图: 代码实现: #include <stdio.h> #include <stdlib.h> #include <time.h> int main() { char gamer; // 玩家出拳 int

shared_ptr线程安全性全面分析_C 语言

正如<STL源码剖析>所讲,"源码之前,了无秘密".本文基于shared_ptr的源代码,提取了shared_ptr的类图和对象图,然后分析了shared_ptr如何保证文档所宣称的线程安全性.本文的分析基于boost 1.52版本,编译器是VC 2010. shared_ptr的线程安全性boost官方文档对shared_ptr线程安全性的正式表述是:shared_ptr对象提供与内置类型相同级别的线程安全性.[shared_ptrobjects offer the sa

为什么要学习C语言 C语言优势分析_C 语言

不止一个学生问到我:"老师,为什么我们的应用程序设计要学C语言而不是别的?C语言不是已经过时了吗?如果现在要写一个Windows程序,用VB或Dephi开发多快呀,用C行吗?退一万步,为什么选择C而不是C++呢?" 这个问题三言两语还真说不全.简单来说,C语言是计算机程序语言的基础,是实用的程序设计工具,学好C语言对你今后学习JAVA.C++.VB等可以打下良好的基础,因为这些语言大部分都是由C语言扩充或衍生而来的.C可以用于开发比较底层的东西,比如驱动.通信协议之类,在Unix和Li

C++变位词问题分析_C 语言

在<编程珠玑>一书的第二章提到了一个变位词问题,变位词指的是一个单词可以通过改变其他单词中字母的顺序来得到,也叫做兄弟单词,如army->mary.由变位词可以引申出几个算法问题,包括字符串包含问题,比较两个字符串是否是变位词,以及找出字典中变位词集合的问题. 一.字符串包含问题 (1) 问题描述:存在字符串1和字符串2,假设字符串2相对较短,如何快速地判定字符串2中的字符都存在于字符串1里(假定字符串只包含字母)? (2) 举例:字符串1为ABCDEFGHIJK,字符串2为ABCDE,

C语言实现选择排序、冒泡排序和快速排序的代码示例_C 语言

选择和冒泡 #include<stdio.h> void maopao(int a[],int len){ int i,j,temp; for(i = 0;i < len - 1 ; i ++){//从第一个到倒数第二个 for (j = 0 ; j < len - 1 - i ; j ++)//排在后的是已经排序的 { if (a[j] > a[j + 1])//大的数换到后面去 { temp = a[j]; a[j] = a[j + 1]; a [j + 1] = tem

C++文件读写代码分享_C 语言

编写一个程序,统计data.txt文件的行数,并将所有行前加上行号后写到data1.txt文件中. 算法提示: 行与行之间以回车符分隔,而getline()函数以回车符作为终止符.因此,可以采用getline()函数读取每一行,再用一个变量i计算行数. (1)实现源代码 #include <iostream> #include <fstream> #include <string> #include <sstream> using namespace std

C语言进制转换代码分享_C 语言

代码很简单,功能也很简单,这里就不多废话了 #include<stdio.h> int main() { char ku[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; int zh[32],i=0,w,j; long int b,y; printf("请输入一个十进制数,我能帮您把它转换成2~16任意进制数:\n"); scanf("%d",&y);