zoukankan      html  css  js  c++  java
  • BitMap再再体验之布隆过滤器

    前言

    还是从一个问题出发,如果需要判断一个元素是否存在应该用什么数据结构?

    比较常用的是HashMap, 我们回到BitMap初体验中的那个问题,给你一台 4G 内存的机器,一组 20 亿个元素(这个元素有可能是字符串,也有可能是一个对象),你怎么判断一个元素是否存在?这个时候我们就需要用到一种数据结构-布隆过滤器。

    实际中的业务场景:redis 的缓存穿透

    什么是布隆过滤器

    布隆过滤器本质上是一种比较巧妙的概率型数据结构,它可以告诉你某个元素一定不存在或者有可能存在

    优势和缺点

    优势:
    相比于HashMap, 它更高效,占用的空间更小

    缺点:
    它的返回结果是概率性的,不是确切的

    实现原理

    当插入一个元素时,将该元素分别输入k个哈希函数,产生k个哈希值,将这些哈希值存到BitMap中。

    当需要查询一个元素时,同样将该元素分别输入k个哈希函数,得到k个哈希值,然后判断这k个哈希值是否都存在。如果有一个哈希值不存在,则说明这个元素一定不存在;如果这k个哈希值都存在,则说明这个元素可能存在(有可能哈希冲突)。

    代码

    首先定义hash函数

    interface HashFunction<T> {
        int hash(T t);
    }
    
    class DefaultHashFunction<T> implements HashFunction<T> {
    
        @Override
        public int hash(T t) {
            return t == null ? 0 : t.hashCode();
        }
    }
    
    class StringHashFunction implements HashFunction<String> {
    
        @Override
        public int hash(String str) {
            if (str == null) {
                return 0;
            }
    
            int hash = 0;
            char[] chars = str.toCharArray();
    
            for (int i = 0; i < chars.length; i++) {
                hash = chars[i] + (hash << 6) + (hash << 16) - hash;
            }
    
            return hash;
        }
    }
    

    构造布隆过滤器

    class BloomFilter {
    
        private BitSet bitSet;
        private int DEFAULT_SIZE = 1 << 30;
        private List<HashFunction<String>> hfs;
    
        public BloomFilter() {
            bitSet = new BitSet(DEFAULT_SIZE);
            hfs = new ArrayList<HashFunction<String>>() {
                {
                    add(new DefaultHashFunction<>());
                    add(new StringHashFunction());
                }
            };
        }
    
        public void add(String value) {
            if (value != null) {
                for (HashFunction<String> hf : hfs) {
                    int hash = hf.hash(value);
                    hash = hash < 0 ? Math.abs(hash) : hash;
                    bitSet.set(hash);
                }
            }
        }
    
        public boolean contains(String value) {
            if (value == null) {
                return false;
            }
    
            for (HashFunction hf : hfs) {
                int hash = hf.hash(value);
                hash = hash < 0 ? Math.abs(hash) : hash;
    
                if (!bitSet.get(hash)) {
                    return false;
                }
            }
    
            return true;
        }
    }
    

    main 方法

    public class Demo {
        public static void main(String[] args) {
    
            BloomFilter bf = new BloomFilter();
            bf.add("boy");
            bf.add("girl");
            bf.add("mike");
            bf.add("jane");
    
            System.out.println(bf.contains("robot"));
            System.out.println(bf.contains("boy"));
    
        }
    }
    
  • 相关阅读:
    代理模式与Android
    图数据库 Titan 高速入门
    怎样编写支持命令行选项的程序
    协方差的意义
    我所理解的Spring AOP的基本概念
    Google搜索解析
    POJ 3311 Hie with the Pie floyd+状压DP
    JS怎样将拖拉事件与点击事件分离?
    C++语言笔记系列之十二——C++的继承
    Mac下Android配置及unity3d的导出Android
  • 原文地址:https://www.cnblogs.com/lwmp/p/13640118.html
Copyright © 2011-2022 走看看