基本概念:
创建一个字节数组,将每一个字节下的8比特位存放某种状态,适用于海量数据,整数,无重复数据的场景,通常用来判断某个数据存不存在
实现原理:
数据是否存在于给定的数据中,其答案无非与是在或者不在,刚好是两种状态,二计算机中比特位的状态正好也是两种状态----0 or 1.那么就可以正好使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,则代表存在。如果为0,则代表不存在.如图
由上图可得,有7个整形,共需要28个字节,但我们使用位图的话,只需要3个字节,且如果数组的最大值不超过23,使用位图的话也只需要三个字节,这就意味着如果要存储一个1,2,3······23的整型数组,我们只需要使用三个字节即可知道其数组里面的值是否存在的情况,而很明显地可以节省很多空间----4X24=96个字节只需要3个字节的存储,而这也就是位图的精妙之处
代码
在Java自带的util包下的BitSet类就已经实现好了位图的功能,其方法主要有这几个:
- set(int val):将val值对应的bit位下标值设置成1
- boolean get(int val):获取val值对应的bit位下标值
- reSet(int vak):将val值对应的bit位下标值重新设置为0
public class bitset { public static void main(String[] args) { //Java自身带的位图类---BitSet BitSet bitSet = new BitSet(11);//开辟nbits/8+1个字节的数组byte[] bytes = new byte[nbits/8+1] int[] arr = {3,9,5,4,0,11}; for(int i = 0; i <arr.length; i++){ bitSet.set(arr[i]);//将整形数组中的数映射到字节数组中,存在的数将位设置为1 } System.out.println(bitSet.get(11));//true System.out.println(bitSet.get(12));//不在数组范围内 --- false } }
模拟实现
定义类
public class myBitSet { //模拟实现位图 public byte[]bytes; public int usedSize; //构造方法 public myBitSet(int n){ //传入的位数 其字节数组长度应设置为:n / 8 +1 最坏的情况也就是当n为8的整数倍时 //会浪费1个字节,当然这也是微乎其微的 //初始数组 bytes = new byte[n /8 +1]; }
set方法 ----- 将目标位下标变成1 或上一个左移bitIndex了的1即可
//set public void set(int val){ //找到数组下标 int arrayIndex = val / 8; //找到一个字节对应位的下标 int bitIndex = val % 8; //将其位下标值设置成1----使用| 不能使用异或^ //如果写成:bytes[arrIndex] = (bytes[arrIndex] | (1 << bitIndex))就需要强制转换 provided:int bytes[arrayIndex] |= (1 << bitIndex);//使用运算符会整形提升,会被提升成int,所以这时候不需要强转 usedSize++; }
get方法 ----- 获取val值对应bit下标的状态位
//get public boolean get(int val){ //数组下标 int arrayIndex = val / 8; //位下标 int bitIndex = val % 8; //&一个1 int ret = bytes[arrayIndex] & (1 << bitIndex); if(ret != 0){ return true; } return false; }
reSet方法:将val对应的位下标重新设置为0
//将val对应的位下标重新设置成0 public void reSet(int val){ //数组下标 int arrayIndex = val / 8; //位下标 int bitIndex = val % 8; //将目标的1变成0,其他的0和1都不变 将1左移bitIndex位后取反再与操作 bytes[arrayIndex] &= ~(1 << bitIndex); usedSize--; }