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:存在
原文地址:https://www.cnblogs.com/lwmp/p/13628426.html