哈希扩展---布隆过滤器(bloom filter)
1>认识布隆过滤器:
可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
随着集合中元素的增加,我们需要的存储空间越来越大,检索速度也越来越慢(O(n),O(logn))。不过世界上还有一种叫作散列表(又叫哈希表,Hash table)的数据结构。它可以通过一个Hash函数将一个元素映射成一个位阵列(Bit array)中的一个点。这样一来,我们只要看看这个点是不是1就可以知道集合中有没有它了。这就是布隆过滤器的基本思想。
使用多个Hash,如果它们有一个说元素不在集合中,那肯定就不在。如果它们都说在,虽然也有一定可能性它们在说谎,不过直觉上判断这种事情的概率是比较低的。
布隆过滤器的应用:网页URL的去重,垃圾邮件的判别,集合重复元素的判别,查询加速(比如基于key-value的存储系统)
注意:对于布隆过滤器来说,存在不一定存在,但不存在一定不存在。
2>布隆过滤器实现:
BitMap.h
typedef struct BitMap
{
int * Bit_bset;//位的集合
int _capacity;
int _size;//有效bit位的个数
}BitMap;
void BitMapInit(BitMap * bmp,int capacity);
void BitMapSet_zero(BitMap * bmp,int pos);
void BitMapSet_one(BitMap *bmp,int pos);
int BitMapTest(BitMap *bmp, int pos);//测试bit位为1还是为0;
int BitMapSize(BitMap *bmp);
int BitMapCount(BitMap *bmp);
void BitMapDestroy(BitMap *bmp);
BitMap.c
#include "BitMap.h"
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
void BitMapInit(BitMap * bmp, int total_Bit){
assert(bmp); //total_Bit代表总共的bit位数
bmp->_capacity = (total_Bit >> 5 )+ 1;//代表需要的整形空间的个数
bmp->Bit_bset = calloc(bmp->_capacity, sizeof(int));//void *calloc(空间的个数,每个空间的字节数);
bmp->_size = total_Bit;//有效比特位的个数
}
//将pos的位置0;
void BitMapSet_zero(BitMap * bmp, int pos){
assert(bmp);
int pos_Byte = pos >> 5;
int pos_Bit = pos % 32;
if (pos > bmp->_size)
return;
bmp->Bit_bset[pos_Byte] = bmp->Bit_bset[pos_Byte] &( ~(1 << pos));
}
//将pos的位置1;
void BitMapSet_one(BitMap *bmp, int pos){
assert(bmp);
int pos_Byte = pos >> 5;
int pos_Bit = pos % 32;
if (pos > bmp->_size)
return;
bmp->Bit_bset[pos_Byte] = bmp->Bit_bset[pos_Byte] |(1 << pos);
}
int BitMapTest(BitMap *bmp, int pos)//测试bit位为1还是为0;
{
assert(bmp);
int pos_Byte = pos >> 5;
int pos_Bit = pos % 32;
if (pos > bmp->_size)
return;
return bmp->Bit_bset[pos_Byte] & (1 << pos);
}
int BitMapSize(BitMap *bmp)
{
assert(bmp);
return bmp->_size;
}
//统计bit位上1的个数
int BitMapCount(BitMap *bmp){
int i = 0;
int count = 0;
assert(bmp);
const char * bit1Count = "\0\1\1\2\1\2\2\3\1\2\2\3\2\3\3\4";
for ( i = 0; i <bmp->_capacity; i++)
{
int value = bmp->Bit_bset[i];
int j = 0;
//一个整数占4个字节,我们按一个字节为单元查看bit位上1的个数
while (j<sizeof(bmp->Bit_bset[0])){
char c = value;
//统计一个字节的底4位
count+=bit1Count[c&0x0f];
c >>= 4;
//统计一个字节的高4位
count+=bit1Count[c&0x0f];
value >>= 8;
j++;
}
}
return count;
}
void BitMapDestroy(BitMap *bmp){
assert(bmp);
if (bmp->Bit_bset)
free(bmp->Bit_bset);
bmp->_size = 0;
bmp->_capacity = 0;
}
BloomFilter.h
#include"BitMap.h"
typedef char* DataType;
typedef int(*pStrToInt)(char *str);
typedef struct BloomFilter{
BitMap _bmp;
int _size;
pStrToInt _StrToInt_method[5];
}BloomFilter;
void BloomFilterInit(BloomFilter *bf, int capacity, pStrToInt *_StrToInt);
int StrToInt1(char *str);
int StrToInt2(char *str);
int StrToInt3(char *str);
int StrToInt4(char *str);
int StrToInt5(char *str);
void BloomFilterInsert(BloomFilter *bf, DataType str);
int IsIn(BloomFilter *bf, DataType str);
BloomFilter.c
#include "BloomFilter.h"
#include<stdlib.h>
#include<stddef.h>
#include<assert.h>
void BloomFilterInit(BloomFilter *bf, int size, pStrToInt _StrtoInt[5]){
int i = 0;
assert(bf);
BitMapInit(&bf->_bmp,size*5);//一个元素对应5个bit位
bf->_size = 0;
for ( i = 0; i < 5; i++)
{
bf->_StrToInt_method[i] = _StrtoInt[i];
}
}
int StrToInt1(char *str){
unsigned int seed = 131; // 31 131 1313 13131 131313
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}
int StrToInt2(char *str){
unsigned int hash = 0;
int i;
for (i = 0; *str; i++)
{
if ((i & 1) == 0)
{
hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
}
else
{
hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
}
}
return (hash & 0x7FFFFFFF);
}
int StrToInt3(char *str){
unsigned int hash = 5381;
while (*str)
{
hash += (hash << 5) + (*str++);
}
return (hash & 0x7FFFFFFF);
}
int StrToInt4(char *str){
unsigned int hash = 1315423911;
while (*str)
{
hash ^= ((hash << 5) + (*str++) + (hash >> 2));
}
return (hash & 0x7FFFFFFF);
}
int StrToInt5(char *str){
unsigned int hash = 0;
unsigned int x = 0;
while (*str)
{
hash = (hash << 4) + (*str++);
if ((x = hash & 0xF0000000L) != 0)
{
hash ^= (x >> 24);
hash &= ~x;
}
}
return (hash & 0x7FFFFFFF);
}
void BloomFilterInsert(BloomFilter *bf,DataType str){
int addr1, addr2, addr3, addr4, addr5;
int TotalBits = bf->_bmp._size;
addr1 = bf->_StrToInt_method[0](str) % TotalBits;
BitMapSet_one(&bf->_bmp, addr1);
addr2 = bf->_StrToInt_method[1](str) % TotalBits;
BitMapSet_one(&bf->_bmp, addr2);
addr3 = bf->_StrToInt_method[2](str) % TotalBits;
BitMapSet_one(&bf->_bmp, addr3);
addr4 = bf->_StrToInt_method[3](str) % TotalBits;
BitMapSet_one(&bf->_bmp, addr4);
addr5 = bf->_StrToInt_method[4](str) % TotalBits;
BitMapSet_one(&bf->_bmp, addr5);
bf->_size++;
}
int IsIn(BloomFilter *bf, DataType str){
int addr1, addr2, addr3, addr4, addr5;
int TotalBits = bf->_bmp._size;
addr1 = bf->_StrToInt_method[0](str) % TotalBits;
if (!BitMapTest(&bf->_bmp, addr1))
return 0;
addr2 = bf->_StrToInt_method[1](str) % TotalBits;
if (!BitMapTest(&bf->_bmp, addr2))
return 0;
addr3 = bf->_StrToInt_method[2](str) % TotalBits;
if (!BitMapTest(&bf->_bmp, addr3))
return 0;
addr4 = bf->_StrToInt_method[3](str) % TotalBits;
if (!BitMapTest(&bf->_bmp, addr4))
return 0;
addr5 = bf->_StrToInt_method[4](str) % TotalBits;
if (!BitMapTest(&bf->_bmp, addr5))
return 0;
return 1;
}