• BitMap 初体验


    前言

    给你一台 4G 内存的机器,一组 20 亿个无序正整数,如何快速地判断一个正整数 N 是否在这组数字中?

    这貌似是一道面试题,大致算一下20亿个整数需要占用的内存:
    java中int类型占4个字节,20亿 * 4 / (1024 * 1024 * 1024) ≈ 7.45G

    BitMap的概念

    简单的说,就是用一个bit位来表示一个特定的意义。比如我们有一个长度为8的bit数组,数组的第一个元素表示0是否存在,数组的第二个元素表示1是否存在。。。那么:
    00000010代表1存在;
    01000010代表1和6存在;
    。。。

    但是一个长度为8的bit数组只能表示7是否存在。如果我们想表示10是否存在呢?那么就需要一个长度为11的bit数组。

    数据结构

    从上面我们可以得到,bit数组的长度取决于最大的那个数值10。

    如果我们用byte数组来存储,那么需要byte数组的长度为 10/8 + 1;

    下面的代码表示一个简单的BitMap的数据结构:

    class BitMap {
        private byte[] bits;
        private int maxValue;
        private int capacity;
    
        public BitMap(int maxValue) {
            this.maxValue = maxValue;
            capacity = (maxValue >> 3) + 1;
            bits = new byte[capacity];
        }
    }
    

    添加数据

    添加数据,需要快速地定位到这个元素要存到byte数组中的哪个位置,这里的位置有两个概念:

    • index : 数据保存在byte数组的哪个索引下;
    • position : 数据在对应的byte中的位置;

    以10为例:

    index = 10 / 8;
    position = 10 % 8;
    

    定位到10需要保存的位置后,怎么把对应位置的bit改为1呢?这里可以用“位或”运算。将10添加到BitMap中的完整步骤如下:

    • 计算index = 10 / 8 = 1;
    • 计算position = 10 % 8 = 2;
    • 将byte[1] 中的数据与 00000100 做“位或”运算(00000100是对1左移2得到的),目的是将对应的bit改为1

    完整的代码如下:

        public void add(int num) {
            int index = num / 8;
            int position = num % 8;
            bits[index] |= (1 << position);
        }
    

    判断数字是否存在

    直接使用“位与”运算即可,代码如下:

        public boolean contains(int num) {
            int index = num / 8;
            int position = num % 8;
            return (bits[index] & (1 << position)) != 0;
        }
    

    main 方法如下

    public class Demo {
        public static void main(String[] args) {
            BitMap bm = new BitMap(100);
            bm.add(1);
            bm.add(13);
            bm.add(57);
            bm.add(100);
    
            System.out.println("3:" + (bm.contains(3) ? "存在" : "不存在"));
            System.out.println("13:" + (bm.contains(13) ? "存在" : "不存在"));
        }
    }
    

    运行结果:

    3:不存在
    13:存在
    
  • 相关阅读:
    Postgresql 修改最大连接数到10000(默认2000多)
    Postgresql 当中有四种方式获取当前时间
    postgreSQL数据库limit分页、排序
    mybatis 中标签bool值类型为false判断
    (转)SpringCloud之服务网关Gateway
    Java线程池,isShutDown、isTerminated的作用与区别
    Java线程池的四种用法与使用场景
    (转)Java多线程:彻底搞懂线程池
    算法注意---1、取用数据之前一定要保证数据存在
    算法与数据结构---4.4、最大子段和-分治优化原理
  • 原文地址:https://www.cnblogs.com/lwmp/p/13628426.html
Copyright © 2020-2023  润新知