位图与布隆过滤器 的说明 介绍

来源:互联网 发布:阿里巴巴服装淘宝网 编辑:程序博客网 时间:2024/05/18 02:46

在平常的编程中 ,我们经常要有一些判断,某个数据  ,,在不在一个文件或者什么中  ???、

如果 是 以前 我们 ,没有 学习 数据 结构 之前,,,我们 一看到这种题目 ,,,我们所能 想到的第一种 方法;就是  使用 二分查找 ,,,但是 这种方法   有限制  成,,,必须是 有序的数据 ,,,,才可使用 这种方法 。。。。
但是 ,,,,在学习数据 结构 之后,我们 就有很多 的 方法来 解决这种 问题 了  。。。。
就比如  ,,,,说我们 可使用 搜索二叉树来 查找数据 ,也可是使用 红黑树来查找 ,,,
算法的时间复杂度都是O(log2 N);;;
那么今天我们就来说一说 同样应用于搜索的两类结构;;;;

1、位图  

之前,,,某个公司的面试 出了这么一道题  ;;;;
有40亿个无符号整型的值,,,,我们要早其中找到某个整型 是否存在 ????假设我们的运行内存为 1G。。
当遇到这种问题的时候 ,,我们就不能 使用上述的方法来实现了 。。。。
为什么呢???
40亿个    unsigned   int     在内存中的容量大致计算得到的   是     大约    16G的内存 ;;;
如果要是使用上面的二叉树来查找的话、、、、、
那么,,,建立的树的大小,,,,远远大于运行 内存  ,,,,,根本无法实现     。。。。
所以,,,在这里我们   引入了一个新的结构————位图————————;  
对于上面说说的那类题型 ,, ,我们要了解到,,我们 所要知道的仅仅是    ,,,,某个数在不在  ,,,,一个集合中 。。。。
所以,,对于这类数据 ,,,,我们 只需要两种 状态来  ,,标记 这些   。。。
所以,,我们 可以使用 一个bit为来表示 这俩种  状态  1或者是  0;;
这种方法就是 我们所说的位图 。。。。。
所以 ,,,对于 位图 的,,结构 ,我们可以只是 使用一个  vector内部存放的数据类型 为size_t ,
也就是 说 一个元素可以表示 8个数据的存在与否 ;;;;
图形结构 显示:::

其中 0表示 ,,,不存在,1表示   存在  ,,
如果要是 使用的是 这种方法的话 ,,,,那么所有的整型值,,,所有建立的vector容器的大小才500M
并且,,,查找的时间复杂度大致相当于O(1);
代码实现
#pragma once#include<vector>class BitMap{public:BitMap(const size_t & n)//n内部表示数据的个数  {_bt.resize((n>>5)+1);//开辟空间}void  Set(const size_t  value)//设置内部值{size_t idex = value>>5;//找到该数存储在那个整型的范围内size_t num  = value %32; //找到在整形的哪个位上_bt[idex] |= (1<<num);//将这位置设置成  1;}void ReSet(const size_t value)//重置{size_t idex =value>>5;size_t num  =value%32;_bt[idex] &= ~(1<<num);//将位置设置 成 0 ;}bool Test(const size_t value){size_t idex = value>>5;size_t num = value%32;if(_bt[idex] & (1<<num))//如果位置上的量是  1  return true;//表示 存在return false;//表示 不存在}protected:vector<size_t> _bt;};void TestBitMap(){BitMap bt((size_t ) -1);bt.Set(1);bt.Set(10432);bt.Set(1034);bt.Set(320);cout<<"1 ?"<<bt.Test(1)<<endl;cout<<"10432 ?"<<bt.Test(10432)<<endl;cout<<"1034 ?"<<bt.Test(1034)<<endl;cout<<"321 ?"<<bt.Test(321)<<endl;bt.ReSet(1034);cout<<"1034 ?"<<bt.Test(1034)<<endl;}
位图的使用大致就是 这个样子了 。。。。。、
但是,我们在平常的编程中 是用的大部分都是 字符串 ,,,,,但是这里有不能来处理 ,,,,,
所以 ,,就要引入我们的新的结构-------布隆过滤器

布隆过滤器

在平常的生活中我们经常要来判断,,一个元素是否在一个集合中,,,;;;;
就好像是,我们要早电话本中查看是否有某人的号码,,,,还有就是 检查一个英文单词的拼写是不是很正确。。
我们经常会想到是,使用的是哈希表,,,,这种数据结构的主要优点就是 :::快速准确,,但又很浪费空间 。。。如果要是,,查找的数据量十分的庞大的话 ,,哈希表的存储效率就会大大的下降  。。。。
如果要是使用的是位图的话,,就可以将这个解决,,但是位图,,无法用来表示 字符串。。。
所以我们 就引入了布隆过滤器这个东西。。。。。

所谓的布隆就是将位图 的特点与哈希表来结合起来 ,,,
但是 ,,,,哈希表有 哈希冲突 ;;
所以 ,,我们 就可以使用 5个位来表示这个字符串,,,,,所以这里就要  熟悉字符串的哈希算法;;;
http://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html
但是 这样。。还是会有冲突的,,,,但是 几率是 十分低的。。。
所以 说 ,,,,布隆只能拿到的是 近似值。。。
换句话说就是,,,,,
在布隆里找一个数据   ,,,,找到的话 ,,,不一定准确,,,但没找到,,一定准确
代码的实现   
#pragma once #include"BitMap.h"#include"HashFunc.h"#include<string>typedef long long  LongType;struct __HashFunc1{template<class T>  size_t BKDRHash(const T *str)  {  register size_t hash = 0;  while (size_t ch = (size_t)*str++)  {         hash = hash * 131 + ch;   // 也可以乘以31、131、1313、13131、131313..  // 有人说将乘法分解为位运算及加减法可以提高效率,如将上式表达为:hash = hash << 7 + hash << 1 + hash + ch;  // 但其实在Intel平台上,CPU内部对二者的处理效率都是差不多的,  // 我分别进行了100亿次的上述两种运算,发现二者时间差距基本为0(如果是Debug版,分解成位运算后的耗时还要高1/3);  // 在ARM这类RISC系统上没有测试过,由于ARM内部使用Booth's Algorithm来模拟32位整数乘法运算,它的效率与乘数有关:  // 当乘数8-31位都为1或0时,需要1个时钟周期  // 当乘数16-31位都为1或0时,需要2个时钟周期  // 当乘数24-31位都为1或0时,需要3个时钟周期  // 否则,需要4个时钟周期  // 因此,虽然我没有实际测试,但是我依然认为二者效率上差别不大          }  return hash;  }  size_t operator()(const string& key){return  BKDRHash(key.c_str());}};struct __HashFunc2{template<class T>  size_t SDBMHash(const T *str)  {  register size_t hash = 0;  while (size_t ch = (size_t)*str++)  {  hash = 65599 * hash + ch;         //hash = (size_t)ch + (hash << 6) + (hash << 16) - hash;  }  return hash;  }size_t operator()(const string& key){return  SDBMHash(key.c_str());}};struct __HashFunc3{template<class T>  size_t RSHash(const T *str)  {  register size_t hash = 0;  size_t magic = 63689;     while (size_t ch = (size_t)*str++)  {  hash = hash * magic + ch;  magic *= 378551;  }  return hash;  }  size_t operator()(const string& key){return  RSHash(key.c_str());}};struct __HashFunc4{template<class T>  size_t APHash(const T *str)  {  register size_t hash = 0;  size_t ch;  for (long i = 0; ch = (size_t)*str++; i++)  {  if ((i & 1) == 0)  {  hash ^= ((hash << 7) ^ ch ^ (hash >> 3));  }  else  {  hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));  }  }  return hash;  }  size_t operator()(const string& key){return  APHash(key.c_str());}};;struct __HashFunc5{template<class T>  size_t JSHash(const T *str)  {  if(!*str)        // 这是由本人添加,以保证空字符串返回哈希值0  return 0;  register size_t hash = 1315423911;  while (size_t ch = (size_t)*str++)  {  hash ^= ((hash << 5) + ch + (hash >> 2));  }  return hash;  }  size_t operator()(const string& key){return  JSHash(key.c_str());}};template<class K,class HashFunc1 = __HashFunc1,class HashFunc2 = __HashFunc2,class HashFunc3 = __HashFunc3,class HashFunc4 = __HashFunc4,class HashFunc5 = __HashFunc5>class BloomFilter{public:BloomFilter(const LongType num):_size(num*10),_bt(num*10){}void  Set(const  K& key){size_t hash1 = HashFunc1()(key);size_t hash2 = HashFunc2()(key);size_t hash3 = HashFunc3()(key);size_t hash4 = HashFunc4()(key);size_t hash5 = HashFunc5()(key);_bt.Set(hash1);_bt.Set(hash2);_bt.Set(hash3);_bt.Set(hash4);_bt.Set(hash5);}bool Test(const  K& key){size_t hash1 = HashFunc1()(key);size_t hash2 = HashFunc2()(key);size_t hash3 = HashFunc3()(key);size_t hash4 = HashFunc4()(key);size_t hash5 = HashFunc5()(key);if(_bt.Test(hash1) == false)return false;if(_bt.Test(hash2) == false)return false;if(_bt.Test(hash3) == false)return false;if(_bt.Test(hash4) == false)return false;return _bt.Test(hash5);}protected:BitMap _bt;LongType _size;};void  TestBloomFilter(){BloomFilter<string> bt(-1);char  * url1 = "http://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html";char  * url2 = "http://www.cnblogs.com/-clq/archive/2012/05/31/2528111.html";char  * url3 = "http://www.cnblogs.com/-clq/archive/2012/05/31/2358111.html";char  * url4  = "http://www.cnblogs.com/-clq/archive/2012/05/31/24328111.html";bt.Set(url1);bt.Set(url2);bt.Set(url3);bt.Set("xiao");bt.Set("xiao1");cout<<url1<<"  "<<bt.Test(url1)<<endl;cout<<url2<<"  "<<bt.Test(url2)<<endl;cout<<url3<<"  "<<bt.Test(url3)<<endl;cout<<url4<<"  "<<bt.Test(url4)<<endl;cout<<"xiao ?"<<" "<<bt.Test("xiao")<<endl;cout<<"xiao1 ?"<<" "<<bt.Test("xiao1")<<endl;}







0 0
原创粉丝点击