菜鸟笔记
提升您的技术认知

bitmap 海量数据处理-ag真人游戏

阅读 : 136

bitmap:

说明:采用一个bit来标记某个value,可以大大节省存储空间。

优点是占用内存少,比如n为一亿(10000 0000),只需要n/8=1250 0000个byte,约等于12mb。缺点为不能重复数据进行排序和查找

 

思想:利用一个byte中的8个bit来表示8个数。某数出现,利用映射将对应bit位置1。

比如元素3,在8bit的映射为

再来个元素5,在8bit的映射为

映射表为:

a[0]->0~7;

a[1]->8~15;

a[2]->16~23;

…….

 

具体实现:(例子为32位)

#include 
#define bitsperword 32
#define shift 5
#define mask 0x1f
//#define n 10000000
#define n 100
 
int a[1   n/bitsperword];//申请内存的大小
 
void set(int i) {
//   a[i>>shift] |=  (1<<(i& mask));
   a[i/bitsperword] |= (0x01<<(i%bitsperword));
}
//clr 初始化所有的bit位为0
void clr(int i) {
//   a[i>>shift] &= ~(1<<(i & mask));
   a[i/bitsperword] &= ~(0x01<<(i%bitsperword));
}
//test 测试所在的bit为是否为1
int test(int i){
   return a[i>>shift] & (0x01<<(i & mask));
}
 
int main()
{  int i;
   for (i = 0; i < n; i  )
       clr(i);
   for(i=0;i

a[i/bitsperword]或a[i>>shift],实现i/32,即求出操作bit所在数的下标。

0x01<<(i%bitsperword)或(1<<(i& mask)),取得该操作bit的具体位置。   实例: 1、 已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数。 思路:8位数,0000 0000~9999 9999,范围为一亿。需要10^8个bit,12m左右字节。 实现:

int const narraysize = 100000000 /(sizeof(int)*8)   1;
int bitmap[narraysize];
void mapphonenumbertobit(int nnumber){
         bitmap[nnumber/ (8*sizeof(int))] |= 0x00000001<<(nnumber%(8*sizeof(int)));
}

 

2、2.5亿个整数中找出不重复的整数的个数,内存空间不足以容纳这2.5亿个整数。

思路:用两个bit来表示一个数。0表示整数未出现,1表示出现一次,2表示出现多次。在遍历这些数的时候,如果对应位置的值是0,则将其置为1;如果是1,将其置为2;如果是2,则保持不变。注意控制与置位的分离。

 

实现

#include    
unsigned char flags[1000]; //数组大小自定义     
unsigned get_val(int idx)  {   
//  |    8 bit  |  
//  |00 00 00 00|  //映射3 2 1 0  
//  |00 00 00 00|  //表示7 6 5 4  
//  ……  
//  |00 00 00 00|  
  
    int i = idx/4;  //一个char 表示4个数,  
    int j = idx%4;    
    unsigned ret = (flags[i]&(0x3<<(2*j)))>>(2*j);    
    //0x3是0011 j的范围为0-3,因此0x3<<(2*j)范围为00000011到11000000 如idx=7 i=1 ,j=3 那么flags[1]&11000000, 得到的是|00 00 00 00|  
    //表示7 6 5 4  
   return ret;    
}    
        
unsigned set_val(int idx, unsigned int val)  {    
    int i = idx/4;    
    int j = idx%4;    
    unsigned tmp = (flags[i]&~((0x3<<(2*j))&0xff)) | (((val%4)<<(2*j))&0xff);    
    flags[i] = tmp;    
    return 0;    
}    
unsigned add_one(int idx)    
{    
    if (get_val(idx)>=2) {  //这一位置上已经出现过了??  
        return 1;    
    }  else  {    
        set_val(idx, get_val(idx) 1);    
        return 0;    
    }    
}    
//只测试非负数的情况;    
//假如考虑负数的话,需增加一个2-bitmap数组.    
int a[]={1, 3, 5, 7, 9, 1, 3, 5, 7, 1, 3, 5,1, 3, 1,10,2,4,6,8,0};    
        
int main()   {    
    int i;    
    memset(flags, 0, sizeof(flags));    
            
    printf("原数组为:");    
    for(i=0;i < sizeof(a)/sizeof(int);   i)  {    
        printf("%d  ", a[i]);    
        add_one(a[i]);    
    }    
    printf("\r\n");    
        
    printf("只出现过一次的数:");    
    for(i=0;i < 100;   i)  {    
        if(get_val(i) == 1)    
            printf("%d  ", i);    
        }    
    printf("\r\n");    
      
    return 0;    
}  

 

3、给你一个文件,里面包含40亿个整数,写一个算法找出该文件中不包含的一个整数, 假设你有1gb内存可用。如果你只有10mb的内存呢?

思路:40亿个整数(40*10^8*4byte~16gb)。

a、 内存为1g

显然无法将16g的数据直接放入1g内存,采用bitmap算法,40*10^8bit= 0.5g(大约),满足1g的内存。

b、 内存为10m

如果我们只有10mb的内存,明显使用bitmap也无济于事了。 内存这么小,注定只能分块处理。比如分块的大小是1000,那么第1块的范围就是0到999,第2块的范围就是1000 到1999……

实际上并不保存这些数,而是给每一个块设置一个计数器。 这样每读入一个数,就在它所在的块对应的计数器加1。处理结束之后,我们找到一个块,它的计数器值小于块大小(1000),说明了这一段里面一定有数字是文件中所不包含的。然后我们单独处理这个块即可。

网站地图