问题的引入:如果我们想去判断一个元素是否存在某个集合里面,会怎么做呢?
一般的方案->先把所有的元素保存起来,然后通过循环的方式来比较确定。但是如果有几千万,甚至上亿的数据的时候,虽然可以通过不同的数据结构来优化,数据检索的时间复杂度,但是整体的效率依然很慢,而且会占用特别多的内存空间。
正确的方案->位图。 基本原理:用一个bit位来存储当前数据是否存在一个状态值,也就是把一个数据通过hash运算取模后,落在bit数组的某个位置中,通过1进行标记。
作用
判断一个数据是否存在某个集合中,可以节约大量的内存,通过一定的错误率换取空间
原理
位图+多个哈希函数
当一个元素被假如到集合中的时候,通过哈希函数把这个元素,映射到一个二进制数组中的某个下标,把这个下标设为1。在进行数据查询与检索的时候,适用同样的方式去映射,只要看到每个下标位置的值是不是1,就可以判断这个元素是否存在于集合中。如果这些点里面有任何位置是0,则表示被检查的元素一定不存在,如果都是1,则表示大概率存在。
优点
1、因为是二进制组成的数据,节约大量内存。 2、基于叔祖的特性,查询和插入的速度很快。 3、因为存储的只有0和1,保密性好。
缺点
1、不能删除
比如,假设你好和hello经过哈希运算,都存在下标为2的位置,所以这个下标为2的位置存储了两个数据。当我们去删除你好的时候,同时也把hello删除了,造成误删。
解决方案:加一个计数器,当下标的计数器引用为1的时候,才能删除。
2、误判
问题1:比如你好,与hello的哈希值是一样的,导致存储你好,结果用hello去判断的时候,出现误判,缺点不能消除,只能降低。 解决方案:增加哈希函数个数,来降低误判率
问题2:如果位图的长度比较短,虽然两个经过哈希计算后,哈希值不同,但是因为通过取模位图长度,得到的索引值相同,还是会出现误判。 解决方案:增加位图的长度,来降低误判率。
适用场景
避免缓存穿透、实现亿级海量数据存储。
延申
布隆过滤器的改造加强版:布谷鸟过滤器