bloom filter的纯C实现

时间:2021-07-09 20:56:32

API定义

/**
*bloom_filter.h
*
*bloom filter算法的API定义和说明。
*这套API没有考虑错误处理,不包含特定hash函数的实现。
*/

#ifndef BLOOM_FILTER_H_INCLUDED
#define BLOOM_FILTER_H_INCLUDED

/**
*bloom filter算法核心类型
*
*核心类型用于定义bloom filter实例,其中包含算法所需的必要数据结构。
*API用户无法也不应该直接访问bloom_filter结构体。
*/
typedef struct bloom_filter *bf_core_type;

/**
*hash回调函数类型
*
*hash函数实现者应该对element元素计算hash值。
*实现者不需要在返回前特意对hash结果模m(m含义见bf_create)。
*/
typedef unsigned long (*bf_hash_handler_type)(void *element);

/**
*创建bloom_filter实例
*
*为bloom_filter实例分配内存并做部分必要的初始化,这是bloom_filter实例生命周期的开始。
*handlers数组包含k个hash函数指针,由API用户自己分配。m设置bloom_filter实例内部记录表比特位长度。
*handlers数组在bloom_filter实例的生命周期内必须始终存在,并且最终由API用户自己负责释放。
*紧接着必须调用bf_clear。
*/
bf_core_type bf_create(bf_hash_handler_type handlers[], unsigned long k, unsigned long m);

/**
*释放bf实例
*
*这是bf实例生命周期的终结。
*这里不会释放bf_create中传入的handlers数组。
*/
void bf_destroy(bf_core_type bf);

/**
*清空bf实例中已有的元素
*
*至少应在bf_create之后调用一次。
*/
void bf_clear(bf_core_type bf);

/**
*向bf实例添加元素element
*/
void bf_add(bf_core_type bf, void *element);

/**
*查询元素element是否在bf实例中
*
*bf中存在element则返回1,否则返回0。
*根据bloom filter算法,返回的结果有一定的错误率。
*/
int bf_has(bf_core_type bf, void *element);

#endif // BLOOM_FILTER_H_INCLUDED

API实现

/**
*bloom_filter.c
*
*bloom filter算法的简单实现,没有错误处理。
*这里的实现并不考虑单个实例在多个线程中的同步问题,但在不同线程中使用不同的bloom filter实例是安全的。
*/

#include <string.h>
#include <stdlib.h>
#include "bloom_filter.h"

struct bloom_filter {
bf_hash_handler_type *handlers;
unsigned char *bitmap;
unsigned long k, m;
};

static inline void bitset(unsigned char *bitmap, unsigned long index) {
bitmap[index>>3]|=1<<(index&7);
}

static inline unsigned char bitget(unsigned char *bitmap, unsigned long index) {
return 1&(bitmap[index>>3]>>(index&7));
}

bf_core_type bf_create(bf_hash_handler_type handlers[], unsigned long k, unsigned long m) {
bf_core_type bf;
bf=malloc(sizeof(struct bloom_filter));
bf->k=k;
bf->m=m;
bf->handlers=handlers;
bf->bitmap=malloc((m+7)>>3);
return bf;
}

void bf_destroy(bf_core_type bf) {
free(bf->bitmap);
free(bf);
}

void bf_clear(bf_core_type bf) {
memset(bf->bitmap, 0, (bf->m+7)>>3);
}

void bf_add(bf_core_type bf, void *element) {
int i;
for(i=0; i<bf->k; i++) {
bitset(bf->bitmap, bf->handlers[i](element)%bf->m);
}
}

int bf_has(bf_core_type bf, void *element) {
int i;
for(i=0; i<bf->k; i++) {
if(!bitget(bf->bitmap, bf->handlers[i](element)%bf->m)) {
return 0;
}
}
return 1;
}

API测试

/**
*test.c
*
*测试和演示bloom filter算法API。
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "bloom_filter.h"

/**
*简单的hash函数实现:直接返回元素的整数值。
*/
unsigned long simple_hash(void *element) {
return *(unsigned long*)element;
}

int main() {
//20组测试数据
unsigned long test[20];
unsigned long test_len=sizeof(test)/sizeof(unsigned long), i;

//bloom filter实例
bf_core_type bf;

//hash回调函数数组
bf_hash_handler_type handlers[]= {simple_hash};
unsigned long handlers_len=sizeof(handlers)/sizeof(bf_hash_handler_type);

//生成20组随机测试数据
srand(time(NULL));
for(i=0; i<test_len; i++) {
test[i]=(unsigned long)rand();
}

//创建和初始化bloom filter实例
bf=bf_create(handlers, handlers_len, 100);
bf_clear(bf);

//添加前10组数据元素
for(i=0; i<test_len/2; i++) {
bf_add(bf, test+i);
}

//查询全部20组数据元素
puts("组号 数据 结果");
for(i=0; i<test_len/2; i++) {
printf("%-6d%-8lu%s\n", i, test[i], bf_has(bf, test+i)?"yes":"no");
}
puts("------------------");
for(; i<test_len; i++) {
printf("%-6d%-8lu%s\n", i, test[i], bf_has(bf, test+i)?"yes":"no");
}

//释放bloom filter实例
bf_destroy(bf);
return 0;
}

bloom filter的纯C实现

测试结果,可以看到有两个错误