元素集合Bloom Filter

本文纯属个人见解,是对前面学习的总结,如有描述不正确的地方还请高手指正~

    一.简介

    

    1.       布隆过滤器 (Bloom Filter)是由Burton Howard Bloom1970年提出实际上是一个很长的二进制量向和一系列随机映射数函

    2.       用于断判一个元素是不是在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的址网判重块模中等等经常被用到。哈希表也能用于断判元素是不是在集合中,但是布隆过滤器只要需哈希表的1/81/4的空间复杂度就可以成完样同的问题。

    3.       它的点优是空间率效和查询时光都远远过超一般的算法,缺陷是有必定的误识别率和删除难题。

    

    二.基本概念

    

    1.       如果想断判一个元素是不是在一个集合里,一般想到的是将有所元素保存起来,然后通过较比肯定。链表,树等等数据结构都是这类路思.,但是元素越来越多,存储空间的需求也越来越大,检索速度慢,所以可以用利散列表(哈希)的数据结构。通过一个Hash数函映射到一位个阵列的一个点。

    2.       1亿个不重复的正整数(大致围范已知),但是只有1G的内存可用,如何断判该围范内的某个数是不是现出在这1亿个数中?最用常的处置方法是用利位图,1*108/1024*1024*8=11.9,也只要需请求12M的内存。(位图要重用于处置整型值一类的问题,而且要求无重复)

    3.       如果是一亿个邮件地址,如何断判邮件地址是不是在1亿个地址中之?这时可以用应Hash表,但是哈希表不能防止产生撞碰,设假一个邮件只占8个字节,为了证保Hash表的撞碰率,使装填因子在0.5阁下,少至要需2*8*10^8/1024*1024*1024 =1.5G存储空间,因此可以用应另外一种数据结构:Bloom Filter.

    

    三.道理:

    

    1.       布隆过滤器要需的是一位个组数(这个和位图有点似类)和k个映射数函(和Hash表似类),在初始状态时,对于长度为m的位组数array,它的有所位都被置为0,如下图所示:

    

                                                                 元素和集合

    

    2.       对于有n个元素的集合S={s1,s2......sn},通过k个映射数函{f1,f2,......fk},将集合S中的个每元素sj(1<=j<=n)映射为k个值{g1,g2......gk},然后再将位组数array中相对应的array[g1],array[g2]......array[gk]置为1

    

                                                     元素和集合

    

    3.       如果要查找某个元素item是不是在S中,则通过映射数函{f1,f2.....fk}到得k个值{g1,g2.....gk},然后再断判array[g1],array[g2]......array[gk]是不是都为1,若全为1,则itemS中,否则item不在S.这个就是布隆过滤器的实现道理.

    每日一道理
一个安静的夜晚,我独自一人,有些空虚,有些凄凉。坐在星空下,抬头仰望美丽天空,感觉真实却由虚幻,闪闪烁烁,似乎看来还有些跳动。美的一切总在瞬间,如同“海市蜃楼”般,也只是刹那间的一闪而过,当天空变得明亮,而这星星也早已一同退去……

    4.       误判的产生有这个可能:就是集合中的若干个元素通过映射以后到得的数值恰巧包含g1,g2,.....gk,那么这类况情下可能会形成误判,但是这个概率很小,一般在万分之一以下:

    5.       布隆过滤器的误判率和这k个映射数函的计划有关

    6.       布隆过滤器是不许允删除元素的,因为若删除一个元素,可能会产生漏判的况情。不过有一种布隆过滤器的变体Counter Bloom Filter,可以持支删除元素

    

    四.用应

    

    1.       布隆过滤器在很多场所能施展很好的效果,比如:网页URL的去重,垃圾邮件的别判,集合重复元素的别判,查询减速(比如基于key-value的存储系统)等

    2.       .有两个URL集合A,B,个每集合中大约有1亿个URL,个每URL64字节,有1G的内存,如何找出两个集合中重复的URL.

    很显然,直接用利Hash表会出超内存制限的围范.这里给出两种路思:

    第一种:如果不许允必定的错误率的话,只有效分治的想思去处理,将A,B两个集合中的URL分离存到若干个文件中{f1,f2...fk}{g1,g2....gk}中,然后取f1g1的内容读入内存,将f1的内容存储到hash_map当中,然后再取g1中的url,有若雷同的url,则写入到文件中,然后直到g1的内容取读毕完,再取g2...gk.然后再取f2的内容读入内存...次依类推,道知找出有所的重复url.

    第二种:如果许允必定错误率的话,则可以用布隆过滤器的想思. 2.在停止网页爬虫时,其中有一个很要重的程过是重复URL的别判,如果将有所的url存入到数据库中,当数据库中URL的量数很多时,在判重时会形成率效低下,此时罕见的一种做法就是用利布隆过滤器,还有一种方法是用利berkeley db来存储urlBerkeley db是一种基于key-value存储的非关系数据库引擎,可以大大提高url判重的率效.

    

    五.例子:

    

#include <string.h>
#include <bitset>
#include <iostream>
#define MAX 2<<24
using namespace std;

//简化n,p 成生m的程过,直接初始化为2<<24小大
bitset<MAX> bloomSet;

//哈希数函的7个子种
int seeds[7] = {3,7,11,13,31,37,61};

//Hash Value
int getHashValue(string str,int n){
	int result = 0;
	int i = 0;
	for(i = 0;i<str.size();i++){
		result = seeds[n]*result+(int)str[i];
		if(result > 2<<24)
			result %= 2<<24;
	}
	return result;
}
//断判是不是在布隆过滤器中
bool isInBloomSet(string str){
	int i;
	for(i = 0;i<7;i++){
		int hash = getHashValue(str,i);
		if(bloomSet[hash] == 0)
			return false;
	}
	return true;
}

//add Elements
void addToBloomSet(string str){
	int i;
	for(int i=0;i<7;i++){
		int hash = getHashValue(str,i);
		bloomSet.set(hash,1);
	}
}

//init the BloomSet
void initBloomSet(){
	addToBloomSet("www.baidu.com");
	addToBloomSet("www.cnblogs.com");
	addToBloomSet("www.google.com");
}

int main(int argc, char *argv[])
{
   int n;
   initBloomSet();
   while(scanf("%d",&n)==1){
	   string str;
	   while(n--){
		   cin >> str;
		   if(isInBloomSet(str)){
			   cout <<"YES"<<endl;
		   }else{
			   cout <<"NO"<<endl;
		   }
	   }
   }
  
   //system("PAUSE");	
   return 0;
}

    
 

    

文章结束给大家分享下程序员的一些笑话语录: 一个合格的程序员是不会写出 诸如 “摧毁地球” 这样的程序的,他们会写一个函数叫 “摧毁行星”而把地球当一个参数传进去。

原文地址:https://www.cnblogs.com/xinyuyuanm/p/3059998.html