bloom filter概念講解以及代碼分析
一. 簡介
1.什么是bloom filter?
Bloom filter 是由 Howard Bloom 在 1970 年提出的二進制向量數(shù)據(jù)結構,它具有很好的空間和時間效率,被用來檢測一個元素是不是集合中的一個成員,這種檢測只會對在集合內的數(shù)據(jù)錯判,而不會對不是集合內的數(shù)據(jù)進行錯判,這樣每個檢測請求返回有“在集合內(可能錯誤)”和“不在集合內(絕對不在集合內)”兩種情況,可見 Bloom filter 是犧牲了正確率換取時間和空間。
2.bloom filter的計算方法?
如需要判斷一個元素是不是在一個集合中,我們通常做法是把所有元素保存下來,然后通過比較知道它是不是在集合內,鏈表、樹都是基于這種思路,當集合內元素個數(shù)的變大,我們需要的空間和時間都線性變大,檢索速度也越來越慢。 Bloom filter 采用的是哈希函數(shù)的方法,將一個元素映射到一個 m 長度的陣列上的一個點,當這個點是 1 時,那么這個元素在集合內,反之則不在集合內。這個方法的缺點就是當檢測的元素很多的時候可能有沖突,解決方法就是使用 k 個哈希 函數(shù)對應 k 個點,如果所有點都是 1 的話,那么元素在集合內,如果有 0 的話,元素則不在集合內。
3.bloom filter的特點?
Bloom filter 優(yōu)點就是它的插入和查詢時間都是常數(shù),另外它查詢元素卻不保存元素本身,具有良好的安全性。它的缺點也是顯而易見的,當插入的元素越多,錯判“在集合內”的概率就越大了,另外 Bloom filter 也不能刪除一個元素,因為多個元素哈希的結果可能在 Bloom filter 結構中占用的是同一個位,如果刪除了一個比特位,可能會影響多個元素的檢測。
二. 代碼實現(xiàn)
現(xiàn)下面在linux下實現(xiàn)了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"
//下面為兩種哈希算法函數(shù)
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
您可能感興趣的文章
- 01-10淺析C#與C++相關概念的比較
- 01-10函數(shù)指針的一些概念詳解
- 01-10C/C++指針小結
- 01-10C#委托所蘊含的函數(shù)指針概念詳細解析
- 01-10關于大小端、位域的一些概念詳解
- 01-10C++中指針和引用的區(qū)別分析
- 01-10c語言指針之二級指針示例
- 01-10C語言棧的表示與實現(xiàn)實例詳解
- 01-10Cocos2d-x 3.x入門教程(一):基礎概念
- 01-10淺析C++編程當中的線程


閱讀排行
本欄相關
- 04-02c語言函數(shù)調用后清空內存 c語言調用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調用函數(shù)求fibo C語言調用函數(shù)求
隨機閱讀
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結
- 04-02jquery與jsp,用jquery
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10delphi制作wav文件的方法