位图布隆过滤器(附面试题)

文章目录

目录

文章目录

前言

一 . 位图

1.1 面试题

1.2 位图概念

1.3 位图的实现

1.4 位图的应用

二 . 布隆过滤器

2.1 布隆过滤器提出

2.2布隆过滤器概念

2.3 布隆过滤器的查找

2.4 实现

2.5 布隆过滤器删除

2.6 布隆过滤器优点

2.7 布隆过滤器缺陷

2.8 布隆过滤器使用场景

三 . 海量数据面试题

1. 哈希切割

2. 位图应用

3.布隆过滤器

总结


前言

大家好,今天给大家带来两种数据结构无位图&布隆过滤器


一 . 位图

学到这里,林林总总也是学了很多的数据结构了,那么位图是一种怎样的数据结构呢?我们由一道面试题来引出

1.1 面试题

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

回顾以往学过的数据结构,最简单想到的或许就是直接遍历 时间复杂度为o(n)

或者先排序o(nlogn)再进行一次二分查找o(logn)

来总结一下 遍历 o(n)  二分查找o(nlogn)+o(logn)

如果面试被问到类似的这种问题,上面两种回答绝对是挂了的,那么我们该用什么来解决这个问题?

在这里引出位图

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比 特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:

1.2 位图概念

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

如上例子,10个整数本应该存放需要40个字节,此时用位图只需要3个字节。

1.3 位图的实现

主要就是三个方法的实现1.插入,2.判断数字是否存在,3.将对应的位置置为零

首先看插入

知道了索引就好办了,其它两个直接照抄即可,给出实现

/*
* 位图
* */
public class MyBitSet {
    private byte[] elem;
    private int usedSize;

    public MyBitSet(){
        elem = new byte[1];
    }

    /**
     * @param n 比特数
     */
    public MyBitSet(int n){
        elem = new byte[n/8+1];
    }

    /**
     * 插入数据
     * @param val 以等价于 将数据的对应
     */
    public void set(int val){
        if(val < 0){
            throw new IndexOutOfBoundsException();
        }
        if(val/8+1 > elem.length){
            elem = Arrays.copyOf(elem, val / 8 + 1);
        }
        int arrayIndex = val/8;
        int bitIndex = val%8;
        elem[arrayIndex] |= (1<<bitIndex);
        usedSize++;
    }

    /**
     * 测试数字是否存在
     * @param val
     * @return
     */
    public boolean get(int val){
        if(val < 0){
            throw new IndexOutOfBoundsException();
        }
        if(val/8+1 > elem.length){
            return false;
        }
        int arrayIndex = val/8;
        int bitIndex = val%8;
        return (elem[arrayIndex] & (1 << bitIndex)) != 0;
    }

    /**
     * 将对应位置置为零
     * @param val
     * @return
     */
    public void reSet(int val){
        if(val < 0){
            throw new IndexOutOfBoundsException();
        }
        if(val/8+1 > elem.length){
            elem = Arrays.copyOf(elem, val / 8 + 1);
        }
        int arrayIndex = val/8;
        int bitIndex = val%8;

        elem[arrayIndex] &= ~(1<<bitIndex);
    }

    /**
     * 当前比特位有多少个1
     * @return
     */
    public int getUsedSize() {
        return this.usedSize;
    }

}

1.4 位图的应用

1. 快速查找某个数据是否在一个集合中(已实现)

2. 排序 + 去重(已实现)

3. 求两个集合的交集、并集等

假设我们有两个位图 A 和 B,分别表示集合 A 和集合 B。要求两个集合的交集,我们可以对位图 A 和位图 B 进行逻辑与操作,得到的结果位图即为两个集合的交集。要求两个集合的并集,我们可以对位图 A 和位图 B 进行逻辑或操作,得到的结果位图即为两个集合的并集。

4. 操作系统中磁盘块标记

二 . 布隆过滤器

2.1 布隆过滤器提出

布隆过滤器(Bloom Filter)是一种空间效率高、误判率低的概率型数据结构,它可以用于判断一个元素是否在一个集合中。布隆过滤器由一个位数组和多个哈希函数组成。当一个元素被加入集合时,它会被哈希函数映射到位数组中的多个位置,将这些位置的值都设为1。查询一个元素是否在集合中时,将该元素经过哈希函数映射到位数组中的多个位置,如果这些位置的值都为1,则说明该元素可能在集合中,否则一定不在。由于哈希函数的随机性,布隆过滤器可能会出现误判,即一个不在集合中的元素被判定为在集合中。但误判率可以通过调整位数组大小和哈希函数个数来控制。

2.2布隆过滤器概念

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

插入

2.3 布隆过滤器的查找

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

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

比如:在布隆过滤器中查找"alibaba"时,假设3个哈希函数计算的哈希值为:1、3、7,刚好和其他元素的比 特位重叠,此时布隆过滤器告诉该元素存在,但实该元素是不存在的。

2.4 实现

/**
 * 简单hash函数
 */
class simpleHash {
    private final int cap;
    private final int seed;
    public simpleHash(int cap,int seed){
        this.cap = cap;
        this.seed = seed;
    }

    public int hash(Object key) {
        int h;
        return (key == null) ? 0 : ((cap-1)*seed)*((h = key.hashCode()) ^ (h >>> 16));
    }
}

/**
 * 布隆过滤器
 */
public class BloomFilter {
    private static final int DEFAULT_SIZE = 1 << 24 ;//方便哈希函数的计算
    private static final int [] seeds = new int []{5,7, 11 , 13 , 31 , 37 , 61};
    private final BitSet bitSet;
    private final simpleHash[] simpleHashes;
    private int size = 0;

    public BloomFilter(){
        // 位图
        bitSet = new BitSet(DEFAULT_SIZE);
        simpleHashes = new simpleHash[seeds.length];
        for(int i = 0; i<seeds.length; i++){
            simpleHashes[i] = new simpleHash(DEFAULT_SIZE,seeds[i]);
        }
    }

    public void set(String str){
        if(str == null) return;
        for (simpleHash simpleHash : simpleHashes) {
            int hash = simpleHash.hash(str);
            bitSet.set(hash);
        }
        size++;
    }

    public boolean contains(String str){
        if(str == null) return false;
        for (simpleHash simpleHash : simpleHashes) {
            int hash = simpleHash.hash(str);
            boolean flag = bitSet.get(hash);
            if(!flag) return false;
        }
        return true;
    }
}

2.5 布隆过滤器删除

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

比如:删除上图中"tencent"元素,如果直接将该元素所对应的二进制比特位置0,“baidu”元素也被删除了, 因为这两个元素在多个哈希函数计算出的比特位上刚好有重叠。

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

缺陷:

1. 无法确认元素是否真正在布隆过滤器中【会有误判】

2. 存在计数回绕【回绕意思为:溢出】


2.6 布隆过滤器优点

1. 增加和查询元素的时间复杂度为:O(K), (K为哈希函数的个数,一般比较小),与数据量大小无关 2. 哈希函数相互之间没有关系,方便硬件并行运算

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

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

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

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

2.7 布隆过滤器缺陷

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

2. 不能获取元素本身

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

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

2.8 布隆过滤器使用场景

1. google的guava包中有对Bloom Filter的实现

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

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

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

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

三 . 海量数据面试题

1. 哈希切割

问 : 给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?, 如何找到top K的IP?

哈希切割

  • 将超过100G的日志文件切分成多个较小的文件,每个文件的大小适合于内存处理。
  • 对每个切分后的文件进行遍历,统计每个IP地址出现的次数。可以使用哈希表(Hash Table)来存储IP地址和对应的出现次数。
  1. 局部top K统计

    • 对每个切分后的文件进行局部统计,得到每个文件的top K IP地址及其出现次数。可以使用小顶堆(Min Heap)来维护当前的top K IP地址。
  2. 合并top K

    • 将每个切分后的文件的top K统计结果进行合并,得到整体的top K IP地址及其出现次数。
  3. 最终top K

    • 对整体的top K统计结果进行合并,得到最终的top K IP地址及其出现次数。

2. 位图应用

1. 给定100亿个整数,设计算法找到只出现一次的整数?

  • 可以使用两个位图来做,在插入某个元素的时候,如果位图1的该位为1,那么就将位图二中该位置修改为一,最后位图1 ^ 位图2,最后得到的结果统计二进制1的个数即可
  • 也可以使用一个位图来解决问题,在插入是给一个元素两个空间的容量,如果全为1,表示出现的次数大于等于两次

2. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

  • 用两个位图存储,再把两个位图&,统计结果中二进制位为1的数量

3. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

可以使用三个位图来解决

  • 如果整数在bitmap1中对应的位为0,则将其置为1,表示整数已经出现过一次;
  • 如果整数在bitmap1中对应的位为1,但在bitmap2中对应的位为0,则将其置为1,表示整数已经出现过两次;
  • 如果整数在bitmap1bitmap2中对应的位都为1,则将其置为1,并将对应的bitmap1bitmap2中的位清零,然后将对应的位在bitmap3中置为1,表示整数已经出现过三次或更多次。

3.布隆过滤器

1. 给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和 近似算法

精准算法

  • 哈希切割进行分块
  • 使用位图进行统计

近似算法

  • 将每个文件分成许多块,每个块包含一定数量的查询。这样每个块的大小可以适应内存的限制。
  • 对于第一个文件,遍历每个块,使用布隆过滤器对查询进行哈希,并将结果保存到磁盘上。对于第二个文件,同样遍历每个块,使用相同的布隆过滤器对查询进行哈希,并将结果保存到磁盘上
  • 遍历第二个文件中的每个查询,使用布隆过滤器检查该查询是否在第一个文件中出现过。

2. 如何扩展BloomFilter使得它支持删除元素的操作

引入计数器

  • 在传统的 Bloom Filter 中,每个哈希函数对应一个位数组的位置,表示元素的存在与否。现在我们可以将每个位置的 0/1 改为一个计数器,用来记录元素的插入次数。

存储计数器的位可由实际情况进行调整


总结

ok,大家多多理解,我们下一篇博客见!

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

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

相关文章

面试官:说说Vue中Proxy与Object.defineProperty的用法与区别

前言 面试时&#xff0c;我们说完Vue响应式原理&#xff0c;或者Vue2和Vue3的区别时&#xff0c;通常会引出Vue3使用了Proxy来优化响应式&#xff0c;而面试官会继续深挖&#xff1a;说说Proxy与Object.defineProperty的区别。 我们不能只说Proxy直接代理一个对象&#xff0c…

【java毕业设计源码】基于SSM框架的在线智能题库管理系统设计与实现

该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等学习内容。 目录 一、项目介绍&#xff1a; 二、文档学习资料&#xff1a; 三、模块截图&#xff1a; 四、开发技术与运行环境&#xff1a; 五、代码展示&#xff1a; 六、数据库表截图&#xff1a…

【论文阅读 + 核心代码定位解读】(2023 AAAI)HiCLR

Hierarchical Consistent Contrastive Learning for Skeleton-Based Action Recognition with Growing Augmentations Contribution 直接使用 strong augmentations 会导致图片/骨架点序列的结构变形和语义信息损失&#xff0c;从而导致训练过程的不稳定。于是本文提出了一种逐…

Java Servlet

请求 请求行 方式 uri http/1.1 请求头 请求体 form表单标签提交Get请求时&#xff0c;参数以键值对形式放在url后&#xff0c;不放在请求体里&#xff0c;Get方式的请求也是可以有请求体的 Post请求时&#xff0c;放在请求头里面 Servlet (server applet) 是运行在服务端…

curl --compressed报错,此版本不支持此命令

出现这个问题是因为微软windows自带的curl不支持这个选项,验证如下 执行where curl 时,可以看到输出为 C:\Windows\System32\curl.ee 解决方法是使用其它curl,下载地址如下 curl for Windows https://curl.se/windows/ 然后把安装目录的bin目录放到path环境变量里最开始, 让…

基于微信小程序的高校活动系统

1 前言 1.1开发背景及意义 高校课余活动管理是中职学生素质教育的重要途径及有效方式&#xff0c;特别是对于一个院校的校园文化建设、校风学风建设和学生综合素质方面的提高至关重要t叫"。良好的学生活动组织可以更好地调动学生参与活动&#xff0c;让学生展示自己的能力…

理解SpringIOC和DI第一课(Spring的特点),IOC对应五大注解,ApplicationContext vs BeanFactory

Spring是一个包含众多工具等Ioc容器 对象这个词在Spring范围内&#xff0c;称为bean Spring两大核心思想 1.IOC (IOC是控制反转&#xff0c;意思是控制权反转-控制权&#xff08;正常是谁用这个对象&#xff0c;谁去创建&#xff0c;&#xff09;-控制对象的控制权&#xf…

十五届海峡两岸电视主持新秀大会竞赛流程

海峡两岸电视主持新秀会是两岸电视媒体共同举办的一项活动&#xff0c;旨在为两岸年轻的电视主持人提供一个展示才华的舞台&#xff0c;促进两岸文化交流和青年交流。本届新秀会是第十二届海峡两岸电视艺术节的重要活动之一。本次竞赛赛制流程如下&#xff1a; &#xff08;1&…

navicat某些表为什么不按主键排序

不知道大家注没注意过navicat的这种情况 为什么不是按主键排序呢 我们来全表扫描看下他的执行计划 explain select * from orsql3; 可以发现不是全表扫描而是索引树扫描&#xff0c;由此得知了共性&#xff0c;不按主键顺序排序的表&#xff0c;肯定是在二级索引上就保存着全部…

【uni-app】赋予你的APP(Android原生)小程序开发能力

采用DCloud(数字天堂&#xff08;北京&#xff09;网络技术有限公司)的uniMPsdk(uni小程序SDK)&#xff0c;是为原生App打造的可运行基于 uni-app 开发的小程序前端项目的框架&#xff0c;从而帮助原生App快速获取小程序的能力。 uni-app文档地址(小程序开发人员开发用) uniMP…

SmartsoftHelp8,条形码,二维码 生成,解析 专业工具

生成条形码 生成二维码 条形码解析 二维码解析 专业工具 下载地址&#xff1a; https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

9、Qt使用随机验证码

一、新建项目 创建一个"Qt Widget Application"项目&#xff0c;基类选择“QMainWindow” 二、自定义CaptchaLabel类 右击项目名&#xff0c;选择"Add New...” C -> CClass&#xff0c;点击“Choose” 更改类名CaptchaLabel&#xff0c;添加基类QLabel&a…

《YOLOv8原创自研》专栏介绍 CSDN独家改进创新实战专栏目录

YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm1001.2014.3001.5482 &#x1f4a1;&#x1f4a1;&#x1f4a1;全网独家首发创新&#xff08;原创&#xff09;&#xff0c;适合paper &#xff01;&#xff01;&#xff01; &#x1f4a1;&a…

分治-归并排序

文章目录 &#x1f31e;315. 计算右侧小于当前元素的个数&#x1f308;1. 题目⛅2. 算法原理&#x1fa90;3. 代码实现 &#x1f315;493. 翻转对&#x1f320;1. 题目⭐2. 算法原理&#x1f31f;3. 代码实现 &#x1f31e;315. 计算右侧小于当前元素的个数 &#x1f308;1. 题…

Matlab数学建模详解之发电机的最佳调度实现

&#x1f517; 运行环境&#xff1a;Matlab、Python &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&am…

String类 ---java

目录 一. 常用的字符串的构造 二. 字符串的源代码 三. 字符串比较 1. 是不能比较字符串的值的 ​编辑 2.比较两个字符串 --- compareTo() 3. 忽略大小写比较 ---compareToIgnoreCase() 四. 字符串转化 1. 数字转字符串 valueOf() 2. 字符串转数字 3. 小写转大写 to…

树莓派多串口通信

树莓派多串口通信 串口配置串口通信函数分析串口通信示例代码 参考博文1&#xff1a;树莓派 4 UART 多串口配置通信参考博文2&#xff1a;树莓派wiringPi库详解关于树莓派相关其他环境配置可参考&#xff1a;快速上手树莓派关于wiringPi库初始化与IO口开发可参考&#xff1a;树…

OpenLayer库的学习入门总结

前言&#xff1a; 作者跟随视频学习ol库的调用与功能实现&#xff0c;进行初步总结与回顾。 声明&#xff1a;参考新中地的文档&#xff0c;进行作者日后复习再次学习的简化。 1、WebGIS简介 GIS的核心概念 GIS&#xff08;Geographic Information System&#xff09;是一…

第 374 场 LeetCode 周赛题解

A 找出峰值 枚举 class Solution { public:vector<int> findPeaks(vector<int> &mountain) {int n mountain.size();vector<int> res;for (int i 1; i < n - 1; i)if (mountain[i] > mountain[i - 1] && mountain[i] > mountain[i 1…

中断方式的数据接收2

Echo实验 回忆之前的实验因为数据处理的过程可以瞬间完成所以可以把数据处理的操作放在中断服务函数中执行 但是数据处理要是时间过长就将数据缓存处理 当使用中断方式接收数据的时候 一般有两种方式 数据处理的时间较短可放在中断服务函数内处理&#xff08;就地处理&#…