数据结构学习篇——布隆过滤器

布隆过滤器的概念

布隆过滤器(英语:Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

布隆过滤器的基本思想

如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合中元素的增加,我们需要的存储空间越来越大。同时检索速度也越来越慢,上述三种结构的检索时间复杂度分别为 O(n),O(logn),O(n/k)。布隆过滤器的原理是,当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。

  • 一个Bloom Filter是基于一个m位的位向量(b1…bm),这些位向量的初始值为0。另外,还有一系列的hash函数(h1…hk),这些hash函数的值域属于1~m。下图是一个bloom filter插入x,y,z幷判断某个值w是否在该数据集的示意图:
    在这里插入图片描述

实现一个布隆过滤器

public class BloomFilter {
  //位图的长度
  public static final int NUM_SLOTS = 1024 * 1024 * 8;
  //hash函数的个数,一个hash函数的结果用于标记一个位
  public static final int NUM_HASH = 8;
  //位图
  private BigInteger bitmap = new BigInteger("0");

  public static void main(String[] args) {
    //测试代码
    BloomFilter bf = new BloomFilter();
    ArrayList<String> contents = new ArrayList<>();
    contents.add("sldkjelsjf");
    contents.add("ggl;ker;gekr");
    contents.add("wieoneomfwe");
    contents.add("sldkjelsvrnlkjf");
    contents.add("ksldkflefwefwefe");

    for (int i = 0; i < contents.size(); i++) {
      bf.addElement(contents.get(i));
    }
    System.out.println(bf.check("sldkjelsvrnlkjf"));
    System.out.println(bf.check("sldkjelnlkjf"));
    System.out.println(bf.check("ggl;ker;gekr"));
  }

  /**将message+n映射到0~NUM_SLOTS-1之间的一个值*/
  private int hash(String message, int n) {
    message = message + String.valueOf(n);
    try {
      //将任意输入映射成128位(16个字节)整数的hash函数
      MessageDigest md5 = MessageDigest.getInstance("md5");
      byte[] bytes = message.getBytes();
      md5.update(bytes);
      byte[] digest = md5.digest();
      //至此,获得message+n的md5结果(128位整数)
      BigInteger bi = new BigInteger(digest);

      return Math.abs(bi.intValue()) % NUM_SLOTS;
    } catch (NoSuchAlgorithmException ex) {
      Logger.getLogger(BloomFilter.class.getName()).log(Level.SEVERE, null, ex);
    }
    return -1;
    // return (int)Math.abs(HashFunctions.bernstein(message,NUM_SLOTS));
  }

  /*处理原始数据
  * 1.hash1(msg)标注一个位……  hash的值域0~NUM_SLOTS-1
  * */
  public void addElement(String message) {
    for (int i = 0; i < NUM_HASH; i++) {
      //代表了hash1,hash2……hash8
      int hashcode = hash(message, i);
      //结果,用于标注位图的该位为1
      if (!bitmap.testBit(hashcode)) {
        //如果还不为1,标注位图的该位为1
        bitmap = bitmap.or(new BigInteger("1").shiftLeft(hashcode));
      }
    }

  }

  public boolean check(String message) {
    for (int i = 0; i < NUM_HASH; i++) {
      int hashcode = hash(message, i);
      //hashcode代表一个位置
      if (!this.bitmap.testBit(hashcode)) {
        //如果位图的该位为0,那么message一定不存在
        return false;
      }
    }
    //不精确,有可能误判
    return true;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值