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);
}
}