文章目录

  • 1. 位图
  • 2. 位图代码
  • 3. 布隆过滤器 Bloom Filter
  • 4. 总结

1. 位图

我们有1千万个整数,整数的范围在1到1亿之间。如何快速查找某个整数是否在这1千万个整数中呢?

  • 当然,这个问题可以用散列表来解决。可以使用一种特殊的散列表,那就是位图
  • 申请一个大小为1亿、布尔类型(true或者false)的数组。将这1千万个整数作为数组下标,将对应的数组值设置成true。比如,整数5对应下标为5的数组值设置为true,也就是array[5]=true。
  • 查询某个整数K是否在这1千万个整数中的时候,只需将array[K]取出来,看是否等于true。如果等于true,那说明1千万整数中包含这个整数K;相反,就表示不包含这个整数K。
  • 不过,很多语言中提供的布尔类型,大小是1个字节的,并不能节省太多内存空间。实际上,表示true和false,只需要**一个二进制位(bit)**就可以了。
  • 我们可以借助编程语言中提供的数据类型,比如int、long、char等类型,通过位运算,用其中的某个位表示某个数字。

2. 位图代码

#include <iostream>
#include <cstring>
using namespace std;
class BitMap
{char *bytes;    //char是1字节,8位int nbits;
public:BitMap(int n){nbits = n;bytes = new char [nbits/8 + 1];memset(bytes, 0, (nbits/8+1)*sizeof(char));}~BitMap(){delete [] bytes;}void set(int k){if(k > nbits)return;int byteIndex = k/8;int bitIndex = k%8;bytes[byteIndex] |= (1<<bitIndex);}bool get(int k){if(k > nbits)return false;int byteIndex = k/8;int bitIndex = k%8;return (bytes[byteIndex] & (1 << bitIndex)) != 0;}void print(){for(int i = 15; i >= 0; --i)cout << get(i) << " ";}
};
int main()
{BitMap bm(8);bm.set(8);cout << bm.get(8) << endl;bm.print();return 0;
}

比如上面例子,如果用散列表存储这1千万的数据,数据是32位的整型数,也就是需要4个字节的存储空间,那总共至少需要40MB的存储空间。如果通过位图的话,数字范围在1到1亿之间,只需要1亿个二进制位,1亿/8/1024/1024 = 12, 也就是12MB左右的存储空间就够了。

不过,这里我们有个假设,就是数字范围不是很大。如果数字的范围很大,数字范围不是1到1亿,而是1到10亿,那位图的大小就是10亿个二进制位,也就是120MB的大小,消耗的内存空间不降反增

怎么办?请布隆过滤器登场!

3. 布隆过滤器 Bloom Filter

  • 布隆过滤器就是为了解决刚刚这个问题,对位图这种数据结构的一种改进。

还是刚刚那个例子,数据个数是1千万,数据的范围是1到10亿。

  • 布隆过滤器的做法是,我们仍然使用一个1亿个二进制大小的位图,然后通过哈希函数,对数字进行处理,让它落在这1到1亿范围内。比如我们把哈希函数设计成f(x) = x%n。其中,x表示数字,n表示位图的大小(1亿),也就是,对数字跟位图的大小进行取模求余。

  • 哈希函数会存在冲突的问题,为了降低冲突概率,可以设计一个复杂点、随机点的哈希函数。除此之外,还有其他方法吗?

  • 我们来看布隆过滤器的处理方法。既然一个哈希函数可能会存在冲突,那用多个哈希函数一起定位一个数据,是否能降低冲突的概率呢?

  • 使用 K 个哈希函数,对同一个数字进行求哈希值,那会得到K个不同的哈希值,我们分别记作X1,X2,X3,……Xk 。我们把这 K 个数字作为位图中的下标,将对应的BitMap[X1],BitMap[X2],BitMap[X3],……BitMap[Xk]都设置成true,也就是说,我们用 K 个二进制位,来表示一个数字的存在。

  • 当我们要查询某个数字是否存在的时候,我们用同样的 K 个哈希函数,对这个数字求哈希值,分别得到Y1,Y2,Y3,……Yk 。看这 K 个哈希值,对应位图中的数值是否都为true,都是true,这个数字存在,任意一个不为true,说明这个数字不存在。

    对于两个不同的数字,经过 K 个哈希函数处理之后,K 个哈希值都相同的概率就非常低了。尽管采用 K 个哈希函数之后,两个数字哈希冲突的概率降低了,但是,这种处理方式又带来了新的问题,那就是容易误判。看下面例子。

  • 布隆过滤器的误判有一个特点,那就是,它只会对存在的情况有误判

  • 如果某个数字经过布隆过滤器判断不存在,那说明这个数字真的不存在,不会误判

  • 如果某个数字经过布隆过滤器判断存在,有可能误判,有可能并不存在。不过,只要我们调整哈希函数的个数、位图大小跟要存储数字的个数之间的比例,那就可以将这种误判的概率降到非常低。

  • 尽管布隆过滤器会存在误判,但是,这并不影响它发挥大作用。很多场景对误判有一定的容忍度

4. 总结

布隆过滤器非常适合这种不需要100%准确的允许存在小概率误判的大规模判重场景。比如统计一个大型网站的每天的UV数,也就是每天有多少用户访问了网站,就可以使用布隆过滤器,对重复访问的用户,进行去重。

布隆过滤器的误判率,主要跟哈希函数的个数位图的大小有关。往布隆过滤器中不停地加入数据之后,位图中不是true的位置就越来越少了,误判率就越来越高了。所以,对于无法事先知道要判重的数据个数的情况,我们需要支持自动扩容的功能。

当布隆过滤器中,数据个数与位图大小比例超过某个阈值的时候,我们就重新申请一个新的位图。后面来的新数据,会被放置到新的位图中。但是,如果我们要判断某个数据是否在布隆过滤器中已经存在,我们就需要查看多个位图,相应的执行效率就降低了一些。

位图、布隆过滤器应用如此广泛,很多编程语言都已经实现了。比如 Java 中的 BitSet 类就是一个位图,Redis 也提供了 BitMap 位图类,Google 的 Guava 工具包提供了BloomFilter 布隆过滤器的实现。

课后思考
1.假设我们有1亿个整数,数据范围是从1到10亿,如何快速并且省内存地给这1亿个数据从小到大排序?

传统做法:1亿个整数,存储需要400M空间
位图算法:数字范围是1到10亿,用位图存储125M就够了,然后将1亿个数字依次添加到位图中,再将位图按下标从小到大输出值为1的下标,排序就完成了,时间复杂度为O(n)

数据结构--位图 BitMap相关推荐

  1. 算法与数据结构——位图BitMap

    一.介绍 1.1 什么是位图 在Java中有四种整数类型:byte.short.int.long. 1 byte(字节) = 8 bit(位) 1 int = 4 byte = 32 bit 所以我们 ...

  2. 十二、【数据结构】位图(bitmap)的详解与实现

    一.定义     --概念部分参考http://www.iteblog.com/archives/148 位图法就是bitmap的缩写.所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据, ...

  3. Redis 04_位图bitmap

    位图bitmap    [字节数组] 位图不是真正的数据类型,它是定义在字符串类型中 一个字符串类型的值最多能存储512M字节的内容 位上限:2^(9+10+10+3)=2^32b  --命令 设置某 ...

  4. 位图BITMAP结构

    数字媒体对于图像的处理肯定离不开对于位图的有关处理,首先要弄清楚位图的结构才能进行下面的工作.位图(Bitmap)图像又称点阵图或光栅图,它使用我们称为像素(象素,Pixel)的一格一格的小点来描述图 ...

  5. 位图Bitmap(基于Java实现)

    所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况.通常是用来判断某个数据存不存在的. 设计原则: 尽可能的最大化利用内存,极限挖掘.利用.发挥Java的性能. ...

  6. 位图bitmap数据结构

    位图是一种很特殊的数据结构,可以利用位图来排序,但是这种排序方法对输入的数据是有比较严格的要求(数据不能重复,大致知道数据的范围).举个例子,假如有一个集合{3,5,7,8,2,1},我们可以用一个8 ...

  7. 【算法数据结构初阶篇】:位图bitMap

    在java中,一个int类型占4个字节,也就是32bit,我们用一个int数组来表示时 new int[32],总计占用内存大概32*32bit,如果说我们存放的海量数据,亿万级非常大,那么这些基本数 ...

  8. 位图BitMap图像的读取与存储

    做图像处理时的源文件一般要用无损的图像文件格式,位图(BitMap)是windows系统下可存储无压缩图像的文件格式.要实现位图文件的读取和存储,首先要明白位图文件的的存储数据结构.位图文件由四部分依 ...

  9. 位图—BitMap和BitSet,布隆过滤器,Roaring Bitmap

    位图 简单来说就是为了压缩节省空间,才出现的. 举个例子: 你要是存储三个数字 2,5,10.这三个数字用java中的short类型来存储,也要6个Byte(short类型的内存空间是2Byte).一 ...

最新文章

  1. Parser Generator Tips翻译(中英对译) by Joshua Xu
  2. 事件绑定机制简单实现
  3. this.counter$ = store.select(fromExample.getCounterCounter)之后马上subscribe
  4. 使用递归判断二叉树对称
  5. freeswitch新增app接口
  6. atitit .大数据的方法,技术.attilax总结 大数据包含哪些方面 v5 s09..docx 7. 三大核心技术:拿数据,处理转换,算数据 2 8. 大数据有5个部分。数据采集,数据存储,
  7. 读书笔记三——你的灯亮着吗
  8. matlab进行分子动力学模拟,一种基于分子动力学模拟测试碳纳米管力学性能的方法与流程...
  9. 更新一波,特殊福利 !
  10. 关于计算机教育的图表,计算机教育箭头环形图表PPT模版.ppt
  11. ubuntu20.04WPS解决缺失字体的问题
  12. 旅行计划 c++_设计旅行计划器
  13. 论坛.newreply.php,discuz!论坛帖、删帖加减金钱值后台设定For D25sp1 4.3日整理版
  14. 阿里巴巴天猫总裁蒋凡被认定为杭州高层次人才
  15. 数组实现-线性表/链表/串/栈的操作
  16. Cisco switch spanning-tree priority 0
  17. 【每日最爱一句】2013.07.24
  18. python绘制红色五角星_python绘制五角星
  19. 使用ZED相机录制事件双目数据集
  20. SQL数据更新、视图

热门文章

  1. smart700iev3 程序下载设置_分享一款Aira2下载工具
  2. 武汉理工大学java,武汉理工大学 web技术基础
  3. 原码、反码、补码,以及负数的位操作
  4. oracle的等保,3.Oracle 检查(部分)
  5. Linux Centos安装步骤
  6. BZOJ 4259: 残缺的字符串 [FFT]
  7. PostgreSQL体系架构
  8. 自己都不觉得自己值钱,别人怎么觉得你值钱?
  9. MTK 升级USB问题
  10. STM32项目(三)——通用LIN控制器