花了3个小时,终于搞懂BitMap了!!!

有这么个需求

如何在3亿个整数(0~2亿)中判断某一个数是否存在?内存限制500M,一台机器。

在这里就用BitMap实现

说代码实现前,先来点基础知识

运算符

  1. 异或运算符(^)

    运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。

  2. 位与(&): 同位上的两个数都是1则位1,否则为0
    位或 (|): 同为上的两个数只要有一个为1 则为1,否则为0

  3. 左移
    左移 << : 8 << 2 : 8*4=32 ,整体左边移动2位,补俩个0,乘以2的平方

  4. 右移
    右移 >>: 8 >>2 : 8 / 4 = 2,整体右边移2位,左边补2个0,除以2的平方

基础知识讲完开始

分析下BitMap

我们知道 一个int占32个bit位。

假如我们用这个32个bit位的每一位的值来表示一个数的话是不是就可以表示32个数字,也就是说32个数字只需要一个int所占的空间大小就可以了,瞬间就可以缩小空间32倍。

比如假设我们有N{1,5,64}个数中最大的是MAX,那么我们只需要开int[MAX /32+1]个int数组就可以存储完这些数据。

Int a : 0000 0000 0000 0000 0000 0000 0000 0000 这里是32个位置,我们可以利用每个位置的0或者1来表示该位置的数是否存在,这样我们就可以得到以下存储结构:具体我们可以画个图来展示

在这里插入图片描述
那我们的1,5,64就是存到了这里边,

假设我们要判断64是否在列表中,那么我们就可以这样来计算:
64/32=2 =>定位到data[2],64%32=0 定位到data[2]的第1位(注意这里从右边开始数)。我们再来看data[2]的第一位是否是1,如果是1则列表中存在64,否则不存在。

这就是bitMap的核心思想。

如果不用int,那么如果换成byte数组来存呢?那么每行就是8位,思想是一样的。

代码实现下,先看byte的实现

byte数组实现BitMap

public class BitMap {

	byte[] bits;		//如果是byte那就一个只能存8个数,一个字节是8位
	int max;			//表示最大的那个数

	public BitMap(int max) {
		this.max = max;
		bits = new byte[(max >> 3) + 1];		//max/8 + 1
	}	
	public void add(int n) {		//往bitmap里面添加数字
		int bitsIndex = n >> 3;		// 除以8 就可以知道在那个byte
		int loc = n & 7;		///这里其实还可以用&运算
		//接下来就是要把bit数组里面的 bisIndex这个下标的byte里面的 第loc 个bit位置为1
		bits[bitsIndex] |= 1 << loc; //或运算
	}
	public void delete(int n){
		int bitsIndex = n >> 3;
		int loc = n & 7;
		bits[bitsIndex] ^= 1 << (loc);//异或运算
	}
	public boolean find(int n) {
		int bitsIndex = n >> 3;		// 除以8 就可以知道在那个byte
		int loc = n & 7;		///这里其实还可以用求余运算,等同于%8
		int flag = bits[bitsIndex] & (1 << loc);	//如果原来的那个位置是0 那肯定就是0 只有那个位置是1 才行
		if(flag == 0) return false;
		return true;
	}
	public static void main(String[] args) {
		BitMap bitMap = new BitMap(200000001);	//10亿
		bitMap.add(2);
		bitMap.add(3);
		bitMap.add(65);
		bitMap.add(66);
		bitMap.delete(66);
		System.out.println(bitMap.find(65));
		System.out.println(bitMap.find(66));
	}
	
}

这里边利用位与运算代替求余运算了。

int数组实现BitMap

public class BitMapByInt {

	int[] data;
	int max;			//表示最大的那个数

	public BitMapByInt(int max) {
		this.max = max;
		data = new int[(max >> 5) + 1];		//max/32 + 1
	}	
	public void add(int n) {		//往bitmap里面添加数字
		int index = n >> 5;		// 除以32 就可以知道在那个int
		int loc = n & 31;		///这里其实还可以用&运算
		//接下来就是要把数组里面的 index这个下标的int里面的 第loc 个bit位置为1
		data[index] |= 1 << loc; //或运算
	}
	public void delete(int n){
		int index = n >> 5;
		int loc = n & 31;
		data[index] ^= 1 << (loc);//异或运算
	}
	public boolean find(int n) {
		int index = n >> 5;		// 除以8 就可以知道在那个byte
		int loc = n & 31;		///这里其实还可以用&运算,等同于%32
		int flag = data[index] & (1 << loc);	//如果原来的那个位置是0 那肯定就是0 只有那个位置是1 才行
		if(flag == 0) return false;
		return true;
	}
	public static void main(String[] args) {
		BitMapByInt map = new BitMapByInt(200000001);	//10亿
		map.add(2);
		map.add(3);
		map.add(65);
		map.add(66);
		map.delete(2);
		System.out.println(map.find(2));
		System.out.println(map.find(3));
	}
}

BitMap的缺点

利用BitMap可以找不重复的数,统计数据,那么也有缺点

  1. 数据不能重复:数据只有0和1 也就是有或者没有 不知道有多个
  2. 数据量少时相对于普通的hash没有优势
  3. 无法处理字符串:hash冲突
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
将一个 Bitmap 对象赋值给另一个 Bitmap 对象,可以使用 `Bitmap.copy()` 方法。这个方法会创建一个新的 Bitmap 对象,并将原始 Bitmap 对象的图像数据复制到新的 Bitmap 对象中。然后,可以回收原始的 Bitmap 对象占用的内存。 以下是一个示例代码: ``` Bitmap originalBitmap = ...; // 原始的 Bitmap 对象 Bitmap newBitmap = originalBitmap.copy(originalBitmap.getConfig(), true); // 创建新的 Bitmap 对象,并复制原始 Bitmap 对象的图像数据 originalBitmap.recycle(); // 回收原始 Bitmap 对象占用的内存 originalBitmap = null; // 将变量置为 null,方便垃圾回收 ``` 需要注意的是,在使用 `Bitmap.copy()` 方法创建新的 Bitmap 对象时,需要指定 Bitmap.Config 参数和 boolean 参数。其中,Bitmap.Config 参数指定新的 Bitmap 对象的像素格式,boolean 参数指定新的 Bitmap 对象是否应该是可变的(即是否可以修改图像数据)。如果将 boolean 参数设置为 true,新的 Bitmap 对象就是可变的。 在回收原始的 Bitmap 对象占用的内存时,可以使用 `Bitmap.recycle()` 方法。但是,如果新的 Bitmap 对象是可变的,就不能在回收原始的 Bitmap 对象之前回收新的 Bitmap 对象占用的内存。否则,新的 Bitmap 对象的图像数据就会丢失。 因此,在将一个 Bitmap 对象赋值给另一个 Bitmap 对象并回收原始的 Bitmap 对象占用的内存时,需要先检查新的 Bitmap 对象是否是可变的,然后再决定是否需要回收它占用的内存。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值