2021.05.12
学习于极客时间[time.geekbang.org/column/arti…]
位图 位图是通过将数组下标与应用中的一些值关联映射,数组中该下标所指定的位置上的元素可以用来标识值的情况。
位图代码
`public class BitMap { // Java中char类型占2个字节,即16bit private char[] bytes; private int nbits;
public BitMap(int nbits) { this.nbits = nbits; this.bytes = new char[nbits/16+1]; }
public void set(int k) { if (k > nbits) return; int byteIndex = k / 16; int bitIndex = k % 16; bytes[byteIndex] |= (1 << bitIndex); }
public boolean get(int k) { if (k > nbits) return false; int byteIndex = k / 16; int bitIndex = k % 16; return (bytes[byteIndex] & (1 << bitIndex)) != 0; } }` (2) 布隆过滤器
布隆过滤器的原理是,当一个元素被加入集合时,通过K个哈希函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就大约知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是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,那就说明这个数字不存在。布隆过滤器非常适合不需要 100% 准确的、允许存在小概率误判的大规模判重场景。
网页爬虫是搜索引擎中的非常重要的系统,同一个网页链接有可能被包含在多个页面中,这就会导致爬虫在爬取的过程中重复爬取相同的网页,那么该如何避免这些重复的爬取呢?
我们用布隆过滤器 (CPU 密集型)来记录已经爬取过的网页链接,假设需要判重的网页有 10 亿,那我们可以用一个 10 倍大小的位图(用以减少误判)来存储,也就是 100 亿个二进制位,换算成字节,那就是大约 1.2GB。如果用散列表判重,需要至少 100GB 的空间。相比来讲,布隆过滤器在存储空间的消耗上,降低了非常多。