大数据算法应用之BitMap

bitMap使用

  • 使用背景

        在数据类型中,byte占1一个字节(8bit),int占4个字节(32bit),long占8个字节(64bit)。当我们要将多个int类型的数据存储为一个数组时,就需要许多的内存,如果我们用byte类型的数组来存储int类型的数据(就可以用一个byte类型的数,表示8个int类型的数据),那会大大减小内存需求。

  • 原理

一个byte类型占内存8位,用二进制表示就是0 0 0 0 0 0 0 0,用数组下标index,以及在元素上的位置来表示一个数据。

   案例介绍

1.{2、7、9、12}这五个数要存在byte数组bytes里面

计算byte数组的长度: 取{2、7、8、9、12}最大值12 , 12/8+1=2,所以bytes长度为2;

bytes初始值:

        bytes[0]: 0 0 0 0 0 0 0 0

        bytes[1]: 0 0 0 0 0 0 0 0

 

数字2进入数组, 2 >> 3 = 0(2右移三位,也就是除以8),2 & 0x07 (2与上7,就是对8取模)= 2,所以2在 bytes[0]的第2个位置上,将第二个位置标志为1

        bytes[0]: 0 0 0 0 0 1 0 0

        bytes[1]: 0 0 0 0 0 0 0 0

  2 >> 3: 00000010  右移三位: 00000000

  2 & 0x07:              0000 0010

                      & 0000 0111

                         = 0000 0010  也就是十进制的2.

数字7进入数组,7 >> 3 = 0,7 & 0x07 = 7,所以7在 bytes[0]的第7个位置上,将第七个位置标志位1

        bytes[0]: 1 0 0 0 0 1 0 0

        bytes[1]: 0 0 0 0 0 0 0 0

 

数字8进入数组,8 >> 3 = 1,8 & 0x07 = 1,所以8在 bytes[1]的第1个位置上,将第1个位置标志位1

        bytes[0]: 1 0 0 0 0 1 0 0

        bytes[1]: 0 0 0 0 0 0 0 1

 

数字9进入数组,9 >> 3 =1,9 & 0x07 = 2,所以9在 bytes[1]的第2个位置上,将第2个位置标志位1

        bytes[0]: 1 0 0 0 0 1 0 0

        bytes[1]: 0 0 0 0 0 0 1 1

 

 

2.{2、7、9、12}这四个数要存在int数组ints里面,即

计算ints数组的长度: 取{2、7、8、9、12}最大值12 , 12/32+1=1,所以ints长度为1;

ints初始值:

         ints [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 0 0   一共32位

 

数字2进入数组, 2 >> 5 = 0(2右移5位,也就是除以32),2 & 0x1F (2与上31,就是对32取模)= 2,所以2在 ints [0]的第2个位置上,将第二个位置标志为1

         ints [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

数字7进入数组,2 >> 5 = 0,7 & 0x1F = 7,所以7在 ints [0]的第7个位置上,将第7个位置标志位1

         ints [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 1 0

数字8进入数组,8 >> 5 = 1,8 & 0x1F = 1,所以8在 ints [0]的第8个位置上,将第8个位置标志位1

         ints [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 1 0 0 0 0 0 1 0

数字9进入数组,9 >> 5=1,9 & 0x1F = 2,所以9在 ints [0]的第9个位置上,将第9个位置标志位1

         ints [0]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 0

  • 优缺点

优点:降低所需内存需要,可以应用来快速查询某个数字是否存在于海量数字之中

缺点:当数据散列比较大时,就会导致数组较大。

Demo


import java.util.Arrays;
import java.util.Random;

public class MyBitMap {
    private long length;
    private static byte[] bitsMapByte; // byte的话是 8位 byte = 1byte=8bit
    private static short[] bitsMapsort; // short是 16位  short =2byte=16bit
    private static int[] bitsMap; // int数组的话,是32位 ,int =4 byte=32bit


    //先看bitsMapByte:
    // 一个byte(-128 ~ 128)内存有8位,0 0 0 0 0 0 0 0,然后我们数组 byte[] bitsMapByte用来存放数据
    //当我们要存入一个int类型的数组int[] arr={5,9,12,8,3},
    // 那么用这个位图表示就是:
    // 3和5在0-7之内,则:(如果是从0开始,那么最低位是从0开始数,如果是从1开始,那么最低位是从1开始数)
    // bitsMapByte[0]: 0 0 1 0 1 0 0 0   =>2的3次方加上2的5次方 =》8+ 32=40 即 bitsMapByte[0]=40
    // 8、9、12在8-17之内
    //        bitsMapByte[1]:  0 0 0 0 0 0 0 0
    //写入8   bitsMapByte[1]:  0 0 0 0 0 0 0 1
    //写入9   bitsMapByte[1]:  0 0 0 0 0 0 1 1
    //写入12  bitsMapByte[1]:  0 0 0 1 0 0 1 1  得到 bitsMapByte[1]=2的零次方  加上 2的 一次方 加上 2的四次方  得到bitsMapByte[1]=19

    //一次类推,得到 bitsMapByte的大小应该为  数组arr的最大值max 除以8 再加上1 ,例如这个案例中arr的最大值 12 ,则bitsMapByte的length应为2
    //构造函数中传入数据中的最大值
    public MyBitMap(long max) {
        this.length = max;
        // 根据长度算出,所需数组大小
        // bitsMap = new int[(int) (max >> 5) + ((max & 31) > 0 ? 1 : 0)];
        bitsMapByte = new byte[(int) (max >> 3) + ((max & 7) > 0 ? 1 : 0)];
    }

    /**
     * a/8得到byte[]的index
     * 获取 a在数组的下标位置  ,例如 a =9,就是 1001 >>3 就是a在 bitsMapByte[1]中
     *
     * @param a
     * @return
     */
    private int getIndex(int a) {
        return a >> 3; //2的三次放为8,如果是int类型的话,就要a>>5
    }

    /**
     * a & 0x07得到在byte[index]的位置
     * 获取 a在元素的位置 ,例如  a =9,a &7 就是 1001 & 111等于 1 即 a在
     *
     * @param a
     * @return
     */
    private int getPosition(int a) {
        return (a & 0x07); //因为是byte,8位,则求与运算得到index  如果是 int数组的话,就要a & 0x1F
    }

    /**
     * 标记指定数字(num)在bitmap中的值,标记其已经出现过<br/>
     * 将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了
     *
     * @param a
     */
    public void put(int a) {
        int index = getIndex(a);
        int position = getPosition(a);
        bitsMapByte[index] |= 1 << position;
    }

    /**
     * 判断指定数字num是否存在<br/>
     * 将1左移position后,那个位置自然就是1,然后和以前的数据做&,判断是否为0即可
     *
     * @param a
     * @return
     */
    public boolean contains(int a) {//判断 那个位置是否为1
        int index = getIndex(a);
        int position = getPosition(a);
        return (bitsMapByte[index] & (1 << position)) != 0;
    }

    public static void showByte(byte b) {
        for (int i = 7; i >= 0; i--) {
            if ((b & (1 << i)) == 0) System.out.print(0 + " ");
            else System.out.print(1 + " ");
        }
    }

    //2147483647
    //

    /**
     *  获取最大的前几位
     * @param arr 结果数组
     */
    public static void getTopMax(int arr[]) {
        int count = 0;
        int length = bitsMapByte.length;
        for (int i = length - 1; i >= 0; i--) {
            for (int j = 8; j > 0; j--) {
                if ((bitsMapByte[i] & (1 << j)) != 0) {
                    arr[count++] = i * 8 + j;
                    if (count>=arr.length) return;//不能用break,break只会进入i的下一此循环
                }
            }
        }
    }

    public static void getBytes(byte[] bytes) {
        Random r = new Random();
        r.nextBytes(bytes);
    }

    public static void main(String args[]) {
        MyBitMap myBitMap = new MyBitMap(10000);
        Random r = new Random();
        int[] originArr = new int[20];
        for (int i = originArr.length - 1; i >= 0; i--) {
            originArr[i] = r.nextInt(10000);
            myBitMap.put(originArr[i]);
        }
        System.out.println(Arrays.toString(originArr));
        int []topFive=new int[5];
        myBitMap.getTopMax(topFive);
        System.out.println(Arrays.toString(topFive));

        //showByte((byte) 5);
    }
}
  •  

转载于:https://my.oschina.net/905042249/blog/3017772

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值