明白了哈希的原理,bit-map就好说了。
bit-map的核心思想是:所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。每一个bit空间都是存储单元,而不像整型数据,即便是int a =1,仍要占用32个字节的空间,当数据量很大时,就会造成严重的空间浪费。由此可见,bit-map可以极大的节省空间,但bit-map只能用来进行一些简单的操作,比如,查询元素是否存在于数据中,数据去重,数据排序等。值得注意的是,数字型数据更适合bit-map,如果是文本记录或者字符串,很难都被哈希函数映射为整型数字。
排序
首先bit-map初始化为全零,通过一个哈希函数,分别将数据映射到bit-map的某一位置,将该位置处数据置1。看一个《编程珠玑》上的例子,元素为{4,7,2,5,3}用bit-map来存储,元素4存储的位置如下:
依次存储:
可以看到这里映射选取的比较简单,同时依次遍历bit-map还完成了排序。
查询元素是否在数据集合中的问题
首先同样哈希函数依次将数据映射标记到bit-map中,查询元素映射到某一位置已经标记为1,判定为存在。当然bit-map这样会出现误判,错误率也很高,效果并不理想,这就是bit-map扩展为bloom filter的原因。因此查询元素是否在数据集合中的问题,应该用布隆过滤器来解决(见下文)。
数据去重问题
例1:)已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。
可以理解为从0-99999999的数字,每个数字对应一个Bit位,所以只需要99M个Bit==12MBytes,这样,就用了小小的12M左右的内存表示了所有的8位数的电话。
同样存储大数据的方法用于以下例子:
2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。大约需要300M左右。这里为了查重,使用两个bit值来表示三种状态,不存在,存在,重复分别标记为00,01,11。将数据依次映射到此bit-map中,最后遍历输出bit-map的key值即可。
Bloom Filter
布隆过滤器可以看成是对bit-map的扩展,它采用K个哈希函数进行映射,这样减少误判,因为每一个元素需要映射K个位置均已标记为1,才说明了这个元素存在于数据集合中。减少误判,并不能做到完全没有。在我们的数据结构或者算法中,往往是牺牲空间得到效率的提升,或者降低效率提高空间的利用率。而布隆过滤器给出了一个新的方法,就是引入了误判率,节省空间,并不降低效率。当数据量很大时,布隆过滤器的效率并不会因此降低,但误判率会提高。因此选取哈希函数的个数k,位数组的大小m以及字符串的量n很重要。
官方文档中给出一个计算公式:K=ln2*(m/n)=0.7(m/n),此时的误判率最低。
以下是使用三个哈希函数的布隆滤波器示意图
判重问题: 将查询的元素经过三个哈希函数映射后,如果三个标记位均为1,说明此元素在数据集合中存在(上面提到,是存在误判的)。