拜托,面试官别问我「位图」了

这是之前面试的时候面试官问到过的一个问题,今天正好看到 布隆过滤器,写篇文章总结一下

我们先看一下流程,流程懂了,问题就解决 90%

我们都知道一个 int4字节,一个字节又有 8个bit位,所以一个 int32位,没毛病吧?

位图就是:我们用一个 int 类型二进制位来表示 0~31的数是否存在。

稍微解释一下:

总体流程就是这样,那么该怎么实现一个位图呢,直接撸code(保姆级注释)。

public class BitMap {
  private int[] bits;

  /**
   * @param max 数字的最大范围
   */
  public BitMap(int max) {
    // (max+1) >> 5  -> (max+1) / 32
    // 这一步的意义就在于,如果数字最大范围 max 等于 10,直接除 32 的话,size 就等于 0 了,相当于做一下边界处理
    int size = (max + 1) >> 5;
    bits = new int[size];
  }

  public void add(int num) {
    // 假如 num == 3
    // num >> 5  -> num / 32,目的在于找到 num 在数组中哪一个位置,比如 35 / 32 = 1,说明 35 在数组下标为 1 的坑里
    int idx = num >> 5;
    // num & 31 >> num % 32 ,35 % 32 = 3,说明 35 在数组下标为 1 的坑里的第 3 位
    int bit = num & 31;
    // 现在我们知道 35 在第一个坑里的第三位,我们现在要把这个第三位设置为 1,先让 1 左移三位,然后或运算到原来的数上
    // 或运算就是 有1为1
    bits[idx] = (1 << bit) | bits[idx];
  }

  public void delete(int num){
    int idx = num >> 5;
    int bit = num & 31;
    // 假如 bits[idx] 的二进制为:1011 1101 0110,假如 num 还是 35,那么 bit == 3
    //           把 1 左移 3 位:0000 0000 1000
    //                    取反:1111 1111 0111
    //  再与 bits[idx] 做与运算: 1011 1101 0110 ,就相当于把第 bit 位置为 0 了
    bits[idx] = (~(1 << bit)) & bits[idx];
  }

  public boolean contains(int num) {
    int idx = num >> 5;
    int bit = num & 31;
    // 假如 bits[idx] 的二进制为:1011 1101 0110,假如 num 还是 35,那么 bit == 3
    //           把 1 左移 3 位:0000 0000 1000
    // 做与运算,如果 bits[idx] 第 3 位为 1,那么和 1 左移 3 位后的结果 作 与运算 肯定就不会为 0 。
    return (bits[idx] & (1 << bit)) != 0;
  }

}

弄清楚位图后我们来看一下位图的场景。

假如我们有 10亿 个数字,假设数字的范围在 0~10 亿,我们现在需要对这些数字进行去重操作。

谈到去重,你一定会想到使用 HashSet的方式,我们都知道一个 int 类型的数字占用 4&#x5B57;&#x8282;,如果 10亿数字中,有 5亿的重复数据,那就需要 5*4 = 20&#x4EBF;&#x5B57;&#x8282;&#x2248; 2G的内存空间。

如果使用位图的方式,我们只需要申请长度为 10&#x4EBF;/32 &#x2248; 3&#x5343;&#x4E07; 的数组,这时候内存占用为 3&#x5343;&#x4E07;*4&#x2248;1.2&#x4EBF;&#x5B57;&#x8282;可以看到使用 &#x4F4D;&#x56FE;HashSet内存占用少了大约 20倍

稍微增加一下难度,我们都知道 int 类型 -> 4字节 -> 32位,范围也就在 21亿的样子

一个手机号 11位,范围是 [100亿,1000亿),如果我们使用之前的存储方式,发现根本没有数据类型能够存储这么大的数据。

这时候就要用到 HashMap分桶的概念了,我们都知道手机的号码段都是前三个都是固定的: 135, 136, 159… 我们可以分为不同的 bit&#x6876;,比如 bits135, bits136, bits159

这时候剩下的手机号还有 8 &#x4F4D;,也就是 [100万,1000万]的范围,这时候就可以用 int 进行存储。

看到这里我相信你已经发现了 位图的特点:

通过二进制位来压缩数据量,同时也存在一个很大的局限性,只能存储数字,且对数字大小还有要求

如果对 10 亿的 IP 进行去重,或者对10亿的 UUID 进行去重,那又该如何设计呢?

这就要引出 位图的 pro 版本bloom filter(布隆过滤器)

Original: https://www.cnblogs.com/Fzeng/p/16101122.html
Author: 小冯同学c
Title: 拜托,面试官别问我「位图」了

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/592983/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • servlet获取表单数据

    Java servlet获取form表单数据(参数) 在 Servlet 中如何使用 HttpServletRequest 获取请求参数和 request 对象传递数据有哪些方法。…

    Java 2023年6月14日
    0106
  • Linux 进程管理

    Linux 进程管理 在 LINUX 中,每个执行的程序都称为一个进程。每一个进程都分配一个 ID 号(pid,进程号)。 每个进程都可能以两种方式存在的。前台与后台,所谓前台进程…

    Java 2023年6月5日
    073
  • Http相关知识

    Http的无状态性 无状态是指,当浏览器发送请求给服务器的时候,服务器响应客户端的请求。但是当同一个浏览器再次发送请求给服务器的时候,服务器并不知道它就是刚才的浏览器。简单的说就是…

    Java 2023年6月13日
    077
  • maven常见问题汇总

    主要记录一些学习及工作时遇到过的一些问题。 1 版本问题 由于版本兼容问题配置maven折腾了一点时间。例:IDEA 2019以上版本与maven3.6.3以上版本不兼容我的笔记本…

    Java 2023年6月8日
    064
  • request.getParameter(“参数名”) 中文乱码解决方法

    解决问题,先要研究问题,URL传中文参数为什么会出现乱码? 原因:Http请求传输时将url以ISO-8859-1编码,服务器收到字节流后默认会以ISO-8859-1编码来解码成字…

    Java 2023年6月5日
    068
  • 一文读懂Java动态代理

    作者 :潘潘日期 :2020-11-22 事实上,对于很多Java编程人员来说,可能只需要达到从入门到上手的编程水准,就能很好的完成大部分研发工作。除非自己强主动获取,或者工作倒逼…

    Java 2023年6月13日
    066
  • 03第三章:【1】_MQTT协议数据包结构

    一、MQTT协议数据包结构 在MQTT协议中,一个MQTT数据包由:固定头(Fixed header)、可变头(Variable header)、消息体(payload)三部分构成…

    Java 2023年5月29日
    050
  • Postman 正确使用姿势

    前言: 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 简介: Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的…

    Java 2023年6月5日
    072
  • [Java]ArrayList源码解析

    ArrayList源码解析 1. 核心源码解读 package java.util; import java.util.function.Consumer; import java…

    Java 2023年6月5日
    060
  • spring boot集成mybatis 出现 nvalid bound statement (not found)

    公司新搭建的项目 再idea中进行springboot集成mybatis时项目能正常启动,但在链接数据库时提示nvalid bound statement (not found) …

    Java 2023年5月30日
    072
  • 断言(assert)简介

    J2SE 1.4在语言上提供了一个新特性,就是assertion功能,他是该版本再Java语言方面最大的革新。 从理论上来说,通过assertion方式可以证明程序的正确性,但是这…

    Java 2023年6月13日
    055
  • java 读取文本 读取每行字符串

    开发中难免遇到一些需要临时处理的问题, 比如产品经理给到你一个TXT文件,帮我把这个数据 怎么怎么样…很急 现在就要 当然这种事情也是见怪不怪 读取文件的代码其实平时用…

    Java 2023年6月5日
    069
  • IDEA 设置文件编码

    打开设置,快捷键 CTRL+ALT+S或点击设置小齿轮。 建议设置成这样,统一编码,配置文件自动转换 ascii 也勾上。最后OK。 对单个文件进行设置编码,在IDEA主窗口右下角…

    Java 2023年6月7日
    0104
  • LeetCode.1170-比较字符串中最小字符的出现频率(Compare Strings by Frequency of the Smallest Char)

    这是小川的第 412次更新,第 444篇原创 看题和准备 今天介绍的是 LeetCode算法题中 Easy级别的第 263题(顺位题号是 1170)。在一个非空字符串s上定义一个函…

    Java 2023年6月5日
    067
  • 单例设计模式

    单例模式: 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。 具体的代码实现: 饿汉式: class Bank { //&#x…

    Java 2023年6月14日
    082
  • 正则表达式

    知识点 &#x6B63;&#x5219;&#x8868;&#x8FBE;&#x5F0F;&#xFF1A;&#x6B63;&a…

    Java 2023年6月5日
    071
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球