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

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

我们先看一下流程,流程懂了,问题就解决 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)

大家都在看

  • 【转】Nginx实现TCP反向代理

    Nginx在1.9.0版本发布以前如果要想做到基于TCP的代理及负载均衡需要通过打名为nginx_tcp_proxy_module的第三方patch来实现,该模块的代码托管在git…

    Java 2023年5月30日
    087
  • 记录idea插件,重装时使用

    1.ignore 2Alibaba Java Coding Guidelines plugin support 3CamelCase–大小写转换 4Cron Descr…

    Java 2023年6月5日
    078
  • Word转换HTML(Java实用版)

    前言: 在业务中,如果需要在浏览器中预览Word文档,或者需要将Word文档转成HTML文件保存,那么本章内容,可以帮助到你。 实现这一功能,有多种实现方式,如:docx4j、po…

    Java 2023年6月8日
    066
  • java-多线程之间的通信

    线程通信的例子:使用两个线程打印 1-100。线程1, 线程2 交替打印 涉及到的三个方法:* wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。* noti…

    Java 2023年5月29日
    086
  • Effective Java 第三版——74. 文档化每个方法抛出的所有异常

    Tips书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code注意,书中的有些代码里方法是基于Java 9…

    Java 2023年5月29日
    084
  • Java课程课堂作业代码

    本文章只是单纯记录课堂老师布置的课堂作业代码,题目都比较简单,所以没有写解题思路,相信大家都能理解,当然其中有的解法和代码不是最优的,当时只是为了完成题目,后来也懒得改了,如果有不…

    Java 2023年6月5日
    0203
  • Django登陆以后重定向到请求登陆的页面

    登陆和注销操作在网页编程上很常见,这两个操作经常需要在操作成功以后转入发出请求的页面。 比如用户正在浏览一篇文章,发现下载该文章的附件需要登录才能进行,这时候点击登陆链接转入登陆页…

    Java 2023年5月29日
    072
  • spring相关面试题

    1、spring有依赖的bean,怎么加载? 2、spring怎么解决循环依赖? https://blog.csdn.net/u010853261/article/details/…

    Java 2023年5月30日
    082
  • Java开发学习(十)—-基于注解开发定义bean

    一、环境准备 先来准备下环境: 创建一个Maven项目 pom.xml添加Spring的依赖 <dependencies> &#xA0; &#xA0;&…

    Java 2023年5月29日
    073
  • RabbitMQ 远程 IP 访问 解决办法 -摘自网络

    java.io.IOExceptionat&#xA0;com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:10…

    Java 2023年5月30日
    075
  • 2018-2021我的开源项目总结

    本人18年6月份毕业在武汉找了第一份 java开发工作4500(面试时被hr压了500,武汉当时行情第一年5000), 做的oa、库存管理相关系统,公司内系统架构主要是ssh,页面…

    Java 2023年6月13日
    081
  • 基于Spring aop写的一个简单的耗时监控

    前言:毕业后应该有一两年没有好好的更新博客了,回头看看自己这一年,似乎少了太多的沉淀了。让自己做一个爱分享的人,好的知识点拿出来和大家一起分享,一起学习。 背景: 在做项目的时候,…

    Java 2023年5月30日
    065
  • 第七周总结-vue脚手架整合SSM-路由配置

    使用axios异步 用户列表 编号 姓名 年&#x9F…

    Java 2023年6月7日
    0105
  • java8特性

    Lambda表达式 lambda表达式:本质就是一个函数式接口的实例对象。 语法: lambda&#x5F62;&#x53C2;&#x5217;&#…

    Java 2023年6月15日
    081
  • 记录Feign调用时对LocalDateTime的处理

    feign api调用参数类型为LocalDateTime一直报错,类型转换错误 简单记录一下解决方式吧 调用方 import org.springframework.contex…

    Java 2023年6月8日
    088
  • Java之控制反转和依赖注入

    1.简介 依赖注入和控制反转,目的是为了使类与类之间解耦合,提高系统的可扩展性和可维护性,下面通过一个例子来引入这一概念。 2.案例 1)一般情况下的类耦合 Main.java 通…

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