Bitmap算法

Posted by Will on August 27, 2017

“walk beside you ”

前言

  人生在世只有一次,不必勉强选择自己不喜欢的路,随性而生或随性而死都没关系,不过,无论选择哪条路,都不要忘记保护自己所珍惜的人。 —— 三代火影


正文

位图:位图的原理就是用一个bit来标识一个数字是否存在,采用一个bit来存储一个数据,所以这样可以大大的节省空间。 例如一个int型有32bit,那么就可以用这32个bit来存储0~31这些整型数据,所以可以将1~31这些数据仅用1个bit来存储,这样节省了空间。 例如要存储1,11,21

   0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

   0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0

   0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

优点:1.运算效率高,不许进行比较和移位;2.占用内存少。

缺点:所有的数据不能重复。即不可对重复的数据进行排序和查找。

使用场景

例如:给一台普通PC,2G内存,要求处理一个包含20亿个不重复并且没有排过序的无符号的int整数,给出一个整数,问如果快速地判断这个整数是否在文件20亿个数据当中? 常规解决方案把20亿个数字放到内存,然后判断。这样的话 20亿个数字 (2000000000*4/1024/1024/1024) = 7.45G 远远大于 2G内存 如果使用Bitmap算法 使用bit来表示 则 (2000000000/8/1024/1024)=238.4M 在Java 中 可以使用BitSet来处理Bitmap算法

代码

public class BitMap {

    byte[] tem;

    public BitMap(int length) {
        this.tem = new byte[length];
    }

    public void add(int num) {
        if (num < tem.length) {
            if (tem[num] != 1) {
                tem[num] = 1;
            }
        }
    }

    public boolean contain(int num) {
        if (num < tem.length) {
            if (tem[num] == 1) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        /*运行前内存*/
        long beforeMemory = Runtime.getRuntime().totalMemory();
        long start1=System.currentTimeMillis();
        BitSet set = new BitSet(2000000000);
        for (int i = 0; i < 2000000000; i++) {
        /*假设999999这个数不在20亿个数里面*/
            if (i != 999999) {
                set.set(i, true);
            }
        }
        /*创建20亿个数后所占内存*/
        long afterMemory = Runtime.getRuntime().totalMemory();
        long end1=System.currentTimeMillis();
        System.out.println("总共内存使用:" + (afterMemory - beforeMemory) / 1024 / 1024 + "MB");
        System.out.println("存入内存耗时:"+(end1-start1)+"毫秒");
        long start2 = System.currentTimeMillis();
        boolean isExit1=set.get(999999);
        boolean isExit2=set.get(900000);

        long end2 = System.currentTimeMillis();

        System.out.println(isExit1);
        System.out.println("20个亿中"+(isExit1?"包含":"不包含")+999999);
        System.out.println("20个亿中"+(isExit2?"包含":"不包含")+900000);
        System.out.println("查询用时:"+(end2 - start2)+"毫秒");
    }
}

输出结果:

    总共内存使用:238MB
    存入内存耗时:8812毫秒
    false
    20个亿中不包含999999
    20个亿中包含900000
    查询用时:0毫秒

可见其效率之高