bitmap与2bitmap实现

Bitmap就是用一个bit位来标记某个元素是否存在,而2Bitmap就是用两个bit为来标记某个元素的个数,00,01,10,11(分别表示0,1,2,3,0表示不存在,1表示存在1次,后面依次)。

Bitmap能用来处理下面的两个问题:

(1)、在2.5亿个整数找出不重复的整数,内存不足以容纳着2.5亿个整数

(2)、腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

对于问题1,整数可能是正数也可能是负数,首先只考虑正整数情况,采用2Bitmap方法,用00表示不存在,01表示出现1次,10表示出现2次及以上,此方法总共需要的内存2^31*2bit = 1Gb = 128MB(32位的正整数有2^31个,每个存储需要2bit,所以就是1Gb,换成字节就是128MB),这样内存就应该能够容纳了,最后在处理完所有的数后,只要输出对应位为01的数即可。如果这2.5亿个数里面既有正数又有负数那么就用两个2Bitmap分别存储正数和负数(取绝对值存储),零就随便放,这是所需要的内存是512MB。

对于问题2,直接用Bitmap即可,0表示存在,1表示不存在。


Bitmap实现:

参考:http://blog.csdn.net/QIBAOYUAN/article/details/5914662

#include <cstdio>
#include <iostream>
using namespace std;
#define WORD 32
#define SHIFT 5 移动5个位,左移则相当于乘以32,右移相当于除以32取整
#define MASK 0x1F //16进制下的31
#define N 1024*1024*1024
int bitmap[1 + N / WORD];
/*
 * 置位函数——用"|"操作符,i&MASK相当于mod操作
 * m mod n 运算,当n = 2的X次幂的时候,m mod n = m&(n-1)
 */
void set(int i) {
    bitmap[i >> SHIFT] |= (1 << (i & MASK));
}
/* 清除位操作,用&~操作符 */
void clear(int i) {
    bitmap[i >> SHIFT] &= ~(1 << (i & MASK));
}
/* 测试位操作用&操作符 */
int test(int i) {
    return bitmap[i >> SHIFT] & (1 << (i & MASK));
}
这里由于int型为32个bit,那么每个bitmap[i]就能保存32个相邻整数是否存在的信息,而为了区分就用余数来表示其位置,例如对于号码 89256,由于89256 mod 32=2789…8,这样我们应该置a[2789]中32位字符串的第8位(从低位数起)为1。

2Bitmap实现:

#include <cstdio>
#include <iostream>
using namespace std;

unsigned char bitmap[1005];

//x表示一个整数,num表示bitmap中已经拥有x的个数
//由于我们只能用2个bit来存储x的个数,所以num的个数最多为3
void set(int x,int num){
    int m = x >> 2;
    int n = x & 3;

    //将x对于为值上的个数值先清零,但是有要保证其他位置上的数不变
    bitmap[m] &= ~((0x3<<(2*n)) & 0xFF);
    //重新对x的个数赋值
    bitmap[m] |= ((num&3)<<(2*n) & 0xFF);
}

void clear(int x){
    int m = x >> 2;
    int n = x & 3;
    bitmap[m] &= ~((0x3<<(2*n)) & 0xFF);
}

unsigned char get(int x){
    int m = x >> 2;
    int n = x & 3;

    return (bitmap[m] & (0x3<<(2*n))) >> (2*n);
}

void add(int x){
    int num = get(x);
    set(x,num+1);
}
上面的&0xFF其实没用,作用就是为了“确保”,unsigned char为8个bit位。

总结:Bitmap是简单快速的数据结构,长用于空间的优化。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值