ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

恋上数据结构与算法 —— 布隆过滤器

2021-06-06 19:33:32  阅读:212  来源: 互联网

标签:函数 二进制位 恋上 误判 布隆 哈希 过滤器 数据结构


布隆过滤器

Bloom Filter(布隆过滤器)。
布隆过滤器是一个很长的二进制向量和映射函数。

用途

布隆过滤器可以用于检索一个元素是否在一个集合中
优点是空间效率和查询时间都会远远超过一般的算法,缺点是有一定的误识别率(针对存在的情况)和删除困难。

实现

布隆过滤器由二进制位和映射函数(Hash函数)组成。

Hash函数: 每个元素经过哈希函数处理后都能生成一个索引位置。
二进制位: 经过hash函数所映射过来的相应索引为会 被置为1.

实现过程

在这里插入图片描述

布隆过滤器的插入值操作:

  1. 待插入的值经过映射函数映射后,得到对应下标。
  2. 在位数组中相应位置就要置为1。

判断某个元素是否在布隆过滤器中的操作:

  1. 当有值要判断在不在布隆过滤器中,只需经过 相同的映射计算,得到的下标。
  2. 如果对应下标位置有为值0的情况,那么该数一定不再布隆过滤器中,如果都是1,则可能存在布隆过滤器中。

出现误判的原因:
不同的字符串可能哈希出来的位置相同(可以适当增加位数组大小或者调整我们的哈希函数来降低概率),如下图所示,B就被误判了。
在这里插入图片描述

布隆过滤器的误判率

误判率受3个因素影响: 二进制位的个数m、哈希函数的个数k、数据规模n

在这里插入图片描述

应用

比特币
分布式系统

复杂度分析

添加、查询的时间复杂度都是O(k),k是哈希函数的个数。
空间复杂度为O(m),m是二进制位数。

代码实现

package filter;

public class BloomFilter<T> {

    private long[] bits;
    //二进制位的个数
    private long bitSize;
    //哈希函数个数
    private int hashSize;

    /**
     * 传入误判率(p)和数据规模(n)
     * 计算所需的二进制向量长度(filterSize)和哈希函数个数(hashSize),从而构造出布隆过滤器
     * @param p 误判率
     * @param n 数据规模
     */
    public BloomFilter(double p, long n){

        if( p <= 0 || p >= 1 || n <= 0) throw  new IllegalArgumentException("Wrong argument!");
        double ln2 = Math.log(2);

        bitSize = (long)   (- (n * Math.log(p)) / (ln2 * ln2));
        hashSize = (int) (bitSize / n * ln2);
        // 1个long型整数有 Long.SIZE位
        bits = new long[(int) ((bitSize + Long.SIZE - 1) / Long.SIZE)];

//        System.out.println( bitSize + " "+ hashSize);
    }

    /**
     * 往布隆过滤器中增加数据
     * @param value
     * @return
     */
    public  boolean put(T value) {

        int hash = value.hashCode();
        int hash1 = hash >>> 16; //取无符号高16位
        boolean result = false;
        for(int i = 1; i <= hashSize; i ++){
            int combinedHash  = hash + (hash1 * i);
            //计算的hash值可能为负数
            if( combinedHash < 0) combinedHash = ~ combinedHash;
//            System.out.println(combinedHash);
            //计算索引
            int index = (int) (combinedHash % bitSize);
            if( set(index) ) result = true;

        }
        return result;
    }

    private boolean set(int index) {
        //把bits数组的每一个元素看成一个桶
        //首先计算落在哪个桶中
        int i = index / Long.SIZE;

        //然后计算在这个桶的第几位
        int j = index % Long.SIZE;

        //保存这个桶的值
        long value = bits[i];
        int bitValue = (1 << j );//1
        bits[i]|= bitValue;
        //只当i桶第j位为0时 也就是没有哈希冲突时返回true
        return (value & bitValue) == 0;
    }

    /**
     * 判断是否在布隆过滤器中
     * @param value
     * @return
     */
    public boolean contains(T value){
        int hash = value.hashCode();
        int hash1 = hash >>> 16; //取无符号高16位
        boolean result = false;
        for(int i = 1; i <= hashSize; i ++){
            int combinedHash  = hash + (hash1 * i);
            //计算的hash值可能为负数
            if( combinedHash < 0) combinedHash = ~ combinedHash;

            //计算索引
            int index = (int) (combinedHash % bitSize);
            if( !get(index) ) return false;

        }
        return true;
    }

    /**
     * 判断index位是否为1
     * @param index
     * @return
     */
    private boolean get(int index) {
        int i = index / Long.SIZE;

        //然后计算在这个桶的第几位
        int j = index % Long.SIZE;
        int bitValue = (int) ((bits[i] >> j) & 1);
        return bitValue == 1;
    }
}


标签:函数,二进制位,恋上,误判,布隆,哈希,过滤器,数据结构
来源: https://blog.csdn.net/weixin_44855907/article/details/117627644

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有