我们考虑存储一些整数,可以用集合去存储,每个int型整数占4byte,是否还有其他更省内存的办法呢?有,位图。
位图的基本单位是bit,一个int型整数有32位,如果我们把每个比特位上1表示该位置的数存在,0表示该位置上的数不存在,那么一个int型整数就可以表示0-31个数字,两个int型整数就可以表示0-63。我们写一个功能实现添加、查询、删除指定数。
public class BitMap {
private final int capacity;
private final int[] arr;
public BitMap(int maxValue) {
//初始化容量和数组大小
capacity = maxValue;
//右移5位相当于除以32,位运算比除法快
arr = new int[(maxValue + 32) >> 5];
//arr = new int[(maxValue + 32) /32];
}
//判断是否存在的逻辑:首先看value落在数组哪个位置上,然后看该位置上的数 value所在的位置上是否为1
public boolean isContains(int value) {
if (value > capacity) {
return false;
}
//value%32等于value&31 位运算比取余快
return (arr[value >> 5] >> (value & 31) & 1) == 1;
//return (arr[value >> 5] >> (value & 31) & 1) == 1;
}
//添加的逻辑:首先看value落在数组哪个位置上,然后将该位置上的数 或上 value所在的位置上置为1的数
//得到该位置上的新数
public void put(int value) {
if (value > capacity) {
System.out.println("超出范围了,无法存放");
return;
}
arr[value >> 5] |= (1 << (value & 31));
}
//删除的逻辑:首先看value落在数组哪个位置上,然后将该位置上的数 与上 value所在的位置上置为0的数
//得到该位置上的新数
public void remove(int value) {
if (!isContains(value)) {
return;
}
arr[value >> 5] &= (~(1 << (value & 31)));
}
public static void main(String[] args) {
BitMap bitMap = new BitMap(100);
bitMap.put(10);
System.out.println(bitMap.isContains(10));
bitMap.put(100);
bitMap.put(100);
System.out.println(bitMap.isContains(100));
bitMap.remove(100);
System.out.println(bitMap.isContains(100));
bitMap.put(200);
bitMap.remove(200);
System.out.println(bitMap.isContains(200));
}
}
上述代码每个比特位标识当前的数字是否存在,充分利用位运算的高效。很有意思。
也可以用long型数组,每个long型整数是64位,所以一个long型整数就可以表示0-63的数字。大家可以自己试一试,原理一样。