位图布隆过滤器的原理及实现

目录

位图的概念:

位图的前置知识:位运算

位图的实现:

位图的基本参数和构造方法:

位图的插入:

位图的查找:

位图的删除:

布隆过滤器概念:

布隆过滤器的实现:

布隆过滤器的基本参数:

布隆过滤器的插入:

布隆过滤器的查找:

布隆过滤器的删除:

布隆过滤器优点:

布隆过滤器缺陷:

布隆过滤器使用场景:


前言:

由于布隆过滤器是由位图实现的且这一数据结构相对其他的内容比较少,故这里就把位图和布隆过滤器一起写下。🌸🌸🌸

有需要本文章源码的友友可以前往:位图源码 / 布隆过滤器源码

位图的概念:

所谓位图,就是用每一位来存放某种状态,适用于海量数据,整数,数据无重复的场景。通常是用来判断某个数据存不存在的。❤️❤️❤️

面试题:

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】

方法1:遍历,时间复杂度O(N)

主要是内存存储不下这么大的数据,故直接遍历不行。

方法2:排序(O(NlogN)),利用二分查找: logN

同样的内存存储不下。

方法3:位图解决

可以解决👍👍👍:数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比 特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。这样就能极大的利用空间。例如(10亿个字节大概是0.9G,可看做是1G,10亿个比特位大概是119兆,看做128兆 )。

🌸位图的前置知识:位运算

下面位图的实现会经常涉及到位运算,故这里讲解一下下面会用到的位运算,如果友友对着部分已经有所了解的话可以跳过❤️❤️❤️。大致可以分为下面三种情况。

(1)确定二进制表示中第x位是0,还是1

这种情况我们可以将1左移k位,最后将 n & (1 << k)即可根据结果是零还是非零(不能==1,因为每个二进制位的权重不一样😭😭😭,这个非常重要)确定二进制表示中第x位是0,还是1。

公式为: n & (1 << k)

(2)将二进制表示的第x位修改成1

不用想了这张图和上面的一样😎为了整齐换了个色。

图是一样的但是运算方法是不一样的这里是 n | (1 << k) 。

公式为: n | (1 << k)

(3)将二进制表示的第x位修改成0

公式为:n & (~(1 << x))

上面三个公式可以说是位运算最基本的公式了,建议大家一定要理解后记住,有一些面试题就是考这个的希望友友一定要熟悉。

🍓位图的实现:

位图的基本参数和构造方法:

在源码中是利用long类型的数组来实现的。

为了方便叙述我们采用byte类型数组进行叙述,其实都一样的无非就是除数不一样而已。 

没有给定大小的话默认给出1个字节也就是8个比特位,有传入参数的话要给n / 8 + 1,这样可能会导致多给一个字节的情况例如(n == 16)理论只要给两个byte但是这里多给了一个(没有关系的)。

public byte[] elem;//利用byte数组来做
    private int usedSize;//表示当前位图有多少个数据

    /**
     * 默认构造方法给出1个字节。
     */
    public MyBitSet(){
        elem = new byte[1];
    }

    /**
     * 根据需要创建大小可能会多创建一个字节,但是没有关系。
     * @param n
     */
    public MyBitSet(int n){
        elem = new byte[n / 8 + 1];
    }

位图的插入:

养成好习惯🌸🌸🌸,如果传入一些明显不符合实际情况的值,要抛一个异常。

异常的名字就根据实际情况来写,异常要单独写一个类。

public class negativeException extends RuntimeException{
    public negativeException(){
        super();
    }
    public negativeException(String message){
        super(message);
    }
}

set:位图的插入,传入负数给出异常(我们这里只写无符号整数的情况,如果要实现负数的话,那就要给对应的数,加上值给他映射成正数的情况) 。因为我们是byte数组8个字节所以除以8,如果是long的话就要除以64,除找到在数组中的对应下标,模是找到具体的bit位。

插入元素一定一定要考虑扩容😎,位图具有去重的作用故如果val已经存入的话直接return即可。

至于如何将对应bit位设置成1在上面位运算已经讲的很明白了,这里就不再赘述。

public void set(int val){
        if(val < 0){
            throw new negativeException("传入负数异常");
        }
        int arrayIndex = val / 8;//计算在byte数组对应下标
        int bitIndex = val % 8;//计算在byte数的具体哪个bit位。
        //插入就有可能会越界
        //要考虑arrayIndex越界的情况。
        if(arrayIndex + 1 > elem.length){
            //越界需要扩容
            elem = Arrays.copyOf(elem,arrayIndex + 1);
        }
        if((elem[arrayIndex] & (1 << bitIndex)) != 0){
            //这个数已经存在
            return;
        }else{
            //这个数不存在
            //把这个数对应关系存入位图
            this.elem[arrayIndex] |= (1 << bitIndex);
            usedSize++;
        }
    }

位图的查找:

判断val数是否在位图中,这个简单,唯一注意点就是越界直接return false不用扩容。其他代码里面都有注释了。

/**
     * 判断val数是否在位图中
     * @param val
     * @return
     */
    public boolean get(int val){
        if(val < 0){
            throw new negativeException("传入负数异常");
        }
        int arrayIndex = val / 8;//计算在byte数组对应下标
        int bitIndex = val % 8;//计算在byte数的具体哪个bit位。
        //防止越界
        if(arrayIndex + 1 > elem.length){
            return false;
        }
        if((elem[arrayIndex] & (1 << bitIndex)) == 0){
            //不存在
            return false;
        }else{
            //存在
            return true;
        }
    }

位图的删除:

运用位图的前置知识:位运算(3)将二进制表示的第x位修改成0来实现位图的删除,具体代码如下所示:🎉🎉🎉

/**
     * 将位图中val对应关系删除
     * @param val
     */
    public void reSet(int val){
        if(val < 0){
            throw new negativeException("负数异常");
        }
        int arrayIndex = val / 8;//计算在byte数组对应下标
        int bitIndex = val % 8;//计算在byte数的具体哪个bit位。
        if(arrayIndex + 1 > elem.length){
            //超过存储大小必定不存在,不存在直接返回
            return;
        }else{
            //先判断存不存在
            if((elem[arrayIndex] & (1 << bitIndex)) != 0){
                //存在
                elem[arrayIndex] &= (~(1 << bitIndex));
                usedSize--;
            }
        }
    }

到这我们位图就已经学完了🎉🎉🎉 ,下面我们将开始介绍布隆过滤器,是基于位图实现的。

效果如下: 

 

布隆过滤器提出:

日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新元素时,将它和集合中的元素直接比较即可。

一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来了。

比如说,一个像 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。

布隆过滤器概念:

布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的一种紧凑型的、比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”,它是用多个哈希函数,将一个数据映射到位图结构中。此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

实现布隆过滤器需要多个哈希函数,为了方便描述我们下面布隆过滤器的代码实现采用下面的哈希函数:

利用随机种子容量来创建不同的哈希函数(可以不一样,只要能区分开来就行)。

class SimpleHash{
    private int cap;//容量
    private int seed;//随机种子
    public SimpleHash(int cap,int seed){
        this.cap = cap;
        this.seed = seed;
    }

    /**
     * 把val字符串变成一个哈希值
     * @param val
     * @return
     */
    public int hash(String val){
        int result = 0;
        for(int i = 0;i < val.length();i++){
            result = result * seed + val.charAt(i);
        }
        return result & (cap - 1);
    }
}

🍒布隆过滤器的实现:

布隆过滤器的基本参数:

 我们定义一个容量大小为2^24次方大小的位图,将多个函数设置为数组(SimpleHash[])方便调用,在调用MyBloomFilter类似通过传进构造方法的参数实现对哈希函数的初始化。😎😎😎

private static final int DEFAULT_SIZE = 1 << 24;
private static final int[] seeds = new int[]{5,7,11,13,31,37,61};//随机数
private BitSet bitSet;//位图
private SimpleHash[] hashFun;
public MyBloomFilter(){
    //创建位图
    bitSet = new BitSet(DEFAULT_SIZE);
    hashFun = new SimpleHash[seeds.length];
    //初始化哈希方法
    for(int i = 0;i < seeds.length;i++){
        hashFun[i] = new SimpleHash(DEFAULT_SIZE,seeds[i]);
    }
}

布隆过滤器的插入:

在位图的插入时是利用多个哈希函数将得到的哈希值对应到位图位置置为1,可能会存在两个不同元素哈希值相同的情况,所以我们说布隆过滤器是比较巧妙的概率型数据结构,它只能表明某样东西一定不存在或者可能存在。

 通过多个哈希函数将对应哈希值映射到位图中。

/**
     * 将字符串value添加到布隆过滤器
     * @param value
     */
    public void set(String value){
        if(value == null){
            return;
        }
        for(SimpleHash fun:hashFun){
            bitSet.set(fun.hash(value));
        }
    }

布隆过滤器的查找:

布隆过滤器的思想是将一个元素用多个哈希函数映射到一个位图中,因此被映射到的位置的比特位一定为1所以可以按照以下方式进行查找:分别计算每个哈希值对应的比特位置存储的是否为零,只要有一个为零, 代表该元素一定不在哈希表中,否则可能在哈希表中。

注意:布隆过滤器如果说某个元素不存在时,该元素一定不存在,如果该元素存在时,该元素可能存在,因为有些哈希函数存在一定的误判

利用位图进行查找。

/**
     * 判断value元素在不在布隆过滤器中,可能有误判
     * @param value
     * @return
     */
    public boolean contains(String value){
        for(SimpleHash fun:hashFun){
            int index = fun.hash(value);
            if(bitSet.get(index) == false){
                return false;
            }
        }
        //会有误判
        return true;
    }

效果如下: 

布隆过滤器的删除:

布隆过滤器不能直接支持删除工作,因为在删除一个元素时,可能会影响其他元素。

一种支持删除的方法:将布隆过滤器中的每个比特位扩展成一个小的计数器,插入元素时给k个计数器(k个哈希函数计算出的哈希地址)加一,删除元素时,给k个计数器减一,通过多占用几倍存储空间的代价来增加删除操作。

👍布隆过滤器优点:

(1)增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关。

(2)哈希函数相互之间没有关系,方便硬件并行运算。

(3)布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势。

(4)在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势。

(5)数据量很大时,布隆过滤器可以表示全集,其他数据结构不能。

(6)使用同一组散列函数的布隆过滤器可以进行交、并、差运算。

😭布隆过滤器缺陷:

(1)有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)。

(2)不能获取元素本身。

(3)一般情况下不能从布隆过滤器中删除元素。

(4)如果采用计数方式删除,可能会存在计数回绕问题。

😎布隆过滤器使用场景:

(1)google的guava包中有对Bloom Filter的实现。

(2) 网页爬虫对URL的去重,避免爬去相同的URL地址。

(3)垃圾邮件过滤,从数十亿个垃圾邮件列表中判断某邮箱是否是垃圾邮箱。       

(4)解决数据库缓存击穿,黑客攻击服务器时,会构建大量不存在于缓存中的key向服务器发起请求,在数 据量足够大的时候,频繁的数据库查询会导致挂机。

(5)秒杀系统,查看用户是否重复购买。

总结:布隆过滤器和位图主要是使用在大量数据的情况,布隆过滤器和位图相比布隆过滤器支持存储除了整形之外的数据类型,而位图只能存储整形🎉🎉🎉。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/533841.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【软件测试之边界值法】

【软件测试之边界值法】(蓝桥杯学习笔记) 我们先来看一个 Java 小程序&#xff0c;如下图所示。 运行这个程序会发生什么事情呢&#xff1f;在这个程序中&#xff0c;目标是为了创建一个有 10 个元素的一维数组&#xff0c;但是&#xff0c;在 Java 语言中&#xff0c;当一个数…

win7无法升级win11,win7无法升级win11系统版本怎么解决

自动微软推出win11后,有不少小伙伴升级安装了。但是,有一些win7用户却安装win11失败,想知道有什么办法能让win7顺利升级win11。关于win7无法升级win11这个问题,最主要原因可能是你的电脑配置不够,毕竟升级win11的门槛要比升级win10还要高,而且还需要支持UEFI安全启动和TP…

Java项目:基于SSM+vue框架实现的人力资源管理系统设计与实现(源码+数据库+毕业论文+任务书)

一、项目简介 本项目是一套基于SSM框架实现的人力资源管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

局域网tcp通信实验

两台windows系统计算机简单TCP通信测试_两台计算机tcp通信-CSDN博客 使用这篇文章的小工具。 环境&#xff1a; 我和同学的两台笔记本电脑。 使用我的手机开热点&#xff0c;两台电脑连接热点。 我的&#xff1a; IPv4 地址 . . . . . . . . . . . . : 192.168.92.79 子…

labview技术交流-如何判断一个数是否为质数

问题起源 如何判断一个数是否为质数&#xff0c;其实并不难&#xff0c;只要你知道质数的定义&#xff0c;按照它的定义去编写代码就可以了。但是没有思路的人可能就会一直找不到方向&#xff0c;所以我就简单介绍一下。 还有我想吐槽的点&#xff0c;labview本来就是很小众的语…

【氧化镓】β-Ga2O3肖特基势垒二极管的缺陷识别

本文是一篇关于β-Ga2O3肖特基势垒二极管在电子辐射和退火调节下缺陷识别的研究。文章首先介绍了β-Ga2O3作为一种高性能器件材料的重要性&#xff0c;然后详细描述了实验方法&#xff0c;包括样品制备、电子辐照、热退火处理以及电学特性和深能级瞬态谱&#xff08;DLTS&#…

英特尔AI训练芯片惊艳亮相:速度与性能双超H200,引领AI新浪潮

英特尔甩出全新AI训练芯片&#xff01;跑千亿大模型速度超H200&#xff0c;罕见披露AI浮点性能 大规模AI计算已经进入系统竞赛。 英特尔在年度Intel Vision大会上重磅推出新一代AI训练芯片Gaudi 3&#xff0c;正面向英伟达旗舰芯片发起挑战。会上&#xff0c;英特尔CEO基辛格挥…

html页面跳转的方法

1、加在head里面 <head> <meta http-equiv"refresh" content"1;urlhttps://ha.huatu.com/zt/hnsylkseo/?"> </head> 2、加在body里面 在body里用js <script language"javascript" type"text/javascript">…

C++感受4-HelloWorld中文版——认识编码

及时了解“编码”对编写代码的影响&#xff0c;是中国程序员越早知道越好的知识点。 一分钟了解什么叫“编码”和“解码”&#xff1b;通过实际演示&#xff0c;充分理解中文Windows下&#xff0c;C源代码编码需要注意的地方&#xff1b;通过 -finput-charsetutf8 等 g 编译配置…

数据可视化-ECharts Html项目实战(11)

在之前的文章中&#xff0c;我们学习了如何在ECharts中特殊图表的双y图以及自定义形状词云图。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 数据可视化-ECh…

【随笔】Git 高级篇 -- 纠缠不清的分支 rebase | cherry-pick(二十四)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

基于特征的多模态生物信号信息检索与自相似矩阵:专注于自动分割

论文地址&#xff1a;Biosensors | Free Full-Text | Feature-Based Information Retrieval of Multimodal Biosignals with a Self-Similarity Matrix: Focus on Automatic Segmentation (mdpi.com) 论文源码&#xff1a;无 期刊&#xff1a;biosensors 这篇论文提出了一种基…

全国项目管理标准化技术委员会副秘书长肖杨先生受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 全国项目管理标准化技术委员会副秘书长、微薄之力&#xff08;北京&#xff09;管理咨询有限公司董事长肖杨先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“数字化时代下&#xff0c;由职能型组织向高度适应性组织转…

GCB Meta分析 | 土壤水分-大气反馈主导全球陆地N2O硝化的排放和反硝化的减少

原名&#xff1a;Soil moisture–atmosphere feedback dominates land N2O nitrification emissions and denitrification reduction 译名&#xff1a;土壤水分-大气反馈主导着陆地N2O硝化的排放和反硝化的减少 期刊&#xff1a;Global Change Biology 通讯作者&#xff1a…

OSCP靶场--Dibble

OSCP靶场–Dibble 考点(前端鉴权参数修改node.js代码注入 suid cp提权 ) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.173.110 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-09 06:36 EDT Nmap scan repor…

Golang | Leetcode Golang题解之第21题合并两个有序链表

题目&#xff1a; 题解&#xff1a; func mergeTwoLists(list1, list2 *ListNode) *ListNode {if list1 nil {return list2 // 注&#xff1a;如果都为空则返回空}if list2 nil {return list1}if list1.Val < list2.Val {list1.Next mergeTwoLists(list1.Next, list2)re…

一分钟了解机器人自由度

目录 自由度的定义 自由度的分类 自由度的影响 影响自由度的主要参数 关节类型和数量 机械结构 控制系统 自由度控制的硬件架构原理 传感器 执行器 控制器 通信接口 软件和算法 机器人的自由度是指机器人在空间中可以独立移动的方向和角度的数量&#xff0c;它是衡…

比特币减半后 牛市爆发

作者&#xff1a;Arthur Hayes of Co-Founder of 100x 编译&#xff1a;Qin jin of ccvalue (以下内容仅代表作者个人观点&#xff0c;不应作为投资决策依据&#xff0c;也不应被视为参与投资交易的建议或意见&#xff09;。 Ping PingPing&#xff0c;我的手机发出的声音&…

【Java】Java使用Swing实现一个模拟计算器(有源码)

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 今天翻了翻之前写的代码&#xff0c;发现自己之前还写了一个计算器&#xff0c;今天把我之前写的代码分享出来。 我记得那会儿刚学不会写&#xff0c;写的乱七八糟&#xff0c;但拿来当期末作业还是不错的哈哈。 直接上…

坚持十天做完Python入门编程100题第三天加班

坚持十天做完Python入门编程100题第三天加班 第24题 扫描文件列表第25题 如何将字典转换成JSON并写入json文件&#xff1f;第26题 JSON转换成字典 第24题 扫描文件列表 如何扫描当前目录下的文件列表&#xff1f;解析&#xff1a;可以使用python内置的glob模块&#xff0c;用法…