BitMap算法原理及实现实现

1. bitmap是什么

bitmap是一个十分有用的结构。所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素。由于采用了Bit为单位来存储数据,因此可以大大节省存储空间。

2. bitmap优势

举个例子,有一个无序有界int数组{1,2,5,7},初步估计占用内存44=16字节,这倒是没什么奇怪的;但是假如有10亿个这样的数呢,10亿4/(102410241024)=3.72G左右。如果这样的一个大的数据做查找和排序,那估计内存也崩溃了,有人说,这些数据可以不用一次性加载,那就是要存盘了,存盘必然消耗IO。

如果用BitMap思想来解决的话,就好很多。一个byte是占8个bit,如果每一个bit的值就是有或者没有,也就是二进制的0或者1,如果用bit的位置代表数组值有还是没有,那么0代表该数值没有出现过,1代表该数组值出现过。也可以描述数据。具体如下图:


现在假如10亿的数据所需的空间就是3.72G/32,一个占用32bit的数据现在只占用了1bit,节省了不少的空间,排序就更不用说了,一切显得那么顺利。这样的数据之间没有关联性,要是读取的,你可以用多线程的方式去读取。时间复杂度方面也是O(Max/n),其中Max为byte[]数组的大小,n为线程大小。

3. bitmap算法代码实现

第一步: 构建特定长度的byte数组(new byte[capacity / 8 + 1]),其中 capacity为整数数组长度(如:10亿个数字、40亿个数字等);

byte[] bits = new byte[getIndex(n) + 1];

第二步 : 计算数字num在byte[]中的位置(num/8);

	/**
	 * num/8得到byte[]的index
	 * @param num
	 * @return
	 */
	public int getIndex(int num){
		return num >> 3;
	}
第三步: 计算数字num在byte[index]的位置(num%8);
	/**
	 * num%8得到在byte[index]的位置
	 * @param num
	 * @return
	 */
	public int getPosition(int num){
		return num & 0x07;
	}
第四步: 将所在的位置从0变成1.其他位置不变;
	/**
	 * 标记指定数字(num)在bitmap中的值,标记其已经出现过<br/>
	 * 将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了
	 * @param bits
	 * @param num
	 */
	public void add(byte[] bits, int num){
		bits[getIndex(num)] |= 1 << getPosition(num);
	}


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


第六步:重置某一数字对应在bitmap中的值;
	/**
	 * 重置某一数字对应在bitmap中的值<br/>
	 * 对1进行左移,然后取反,最后与byte[index]作与操作。
	 * @param bits
	 * @param num
	 */
	public void clear(byte[] bits, int num){
		bits[getIndex(num)] &= ~(1 << getPosition(num));
	}


测试代码如下:

	/**
	 * 创建bitmap数组
	 */
	public byte[] create(int n){
		byte[] bits = new byte[getIndex(n) + 1];
		
		for (int i = 0; i < n; i++){
			add(bits, i);
		}
		
		System.out.println(contains(bits, 11));
		int index = 1;
		for (byte bit : bits) {
			System.out.println("-------" + index++ + "-------");
			showByte(bit);
		}
		
		return bits;
	}
	
	/**
	 * 标记指定数字(num)在bitmap中的值,标记其已经出现过<br/>
	 * 将1左移position后,那个位置自然就是1,然后和以前的数据做|,这样,那个位置就替换成1了
	 * @param bits
	 * @param num
	 */
	public void add(byte[] bits, int num){
		bits[getIndex(num)] |= 1 << getPosition(num);
	}
	
	/**
	 * 判断指定数字num是否存在<br/>
	 * 将1左移position后,那个位置自然就是1,然后和以前的数据做&,判断是否为0即可
	 * @param bits
	 * @param num
	 * @return
	 */
	public boolean contains(byte[] bits, int num){
		return (bits[getIndex(num)] & 1 << getPosition(num)) != 0;
	}
	
	/**
	 * num/8得到byte[]的index
	 * @param num
	 * @return
	 */
	public int getIndex(int num){
		return num >> 3;
	}
	
	/**
	 * num%8得到在byte[index]的位置
	 * @param num
	 * @return
	 */
	public int getPosition(int num){
		return num & 0x07;
	}
	
	/**
	 * 重置某一数字对应在bitmap中的值<br/>
	 * 对1进行左移,然后取反,最后与byte[index]作与操作。
	 * @param bits
	 * @param num
	 */
	public void clear(byte[] bits, int num){
		bits[getIndex(num)] &= ~(1 << getPosition(num));
	}
	
	/**
	 * 打印byte类型的变量<br/>
	 * 将byte转换为一个长度为8的byte数组,数组每个值代表bit
	 */
	public void showByte(byte b) {
		byte[] array = new byte[8];
		for (int i = 7; i >= 0; i--) {
			array[i] = (byte)(b & 1);
			b = (byte) (b >> 1);
		}
		
		for (byte b1 : array) {
			System.out.print(b1);
			System.out.print(" ");
		}
		
		System.out.println();
	}
	
	@Test
	public void test(){
		int n = 1000000000;
		create(n);
	}


参考文章:

http://www.jianshu.com/p/6082a2f7df8e

http://www.cnblogs.com/huangxincheng/archive/2012/12/06/2804756.html


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值