bitmap思想和2-Bitmap 实现

本文介绍了一种利用Bitmap思想解决大量电话号码中重复号码查找问题的方法,通过使用位图存储和操作,实现了在内存占用较小的情况下,快速识别重复电话号码。包括二进制位图和双位图两种实现方式,适用于处理大规模数据集。
1. Bit-map思想

给你一堆西安市的电话号码列表,数量大概在千万级,要求从中找出所有重复的电话号码,需要时间复杂度尽可能小。

目前西安市的电话号码大概都以8开头,为8位,也就是类似于82678578这样子

二重暴力搜索时间复杂度太高,这里我们不予考虑。

容易想到的办法就是建立一个标志数组,int boolean都行,用相应的位置值来代替这个号码是否出现,

根据数组的可直接存取特性,来提高效率。但是你是否想过或测试过

int[] a = new int[100000000];

boolean[] a = new boolean[100000000]; //需要大概100M*4的内存,如果

这样类似的语句是否可以通过编译并且执行。

再仔细思考下,就会发现,int型的字段太过于占空间,我们只需要知道这个号码存在与否,

所以最简单的0和1就够用了,能表示0和1的最小存储单位是什么呢?

是内存中的一位。//int 为4 byte  ,那么1个int 可以存放32位;

申请一个int一维数组,那么可以当作为列为32位的二维数组,

            |                            32位                                      |

int a[0] |0000000000000000000000000000000000000|

int a[1] |0000000000000000000000000000000000000|

………………

int a[N] |0000000000000000000000000000000000000|

每一个电话号码,用上面的一位表示,如电话80000000可以用a[0]的第一位表示,有则是表示为1,无则是0

OK,这就是bitmap的思想。

将西安市的电话号码去掉开头的8,就可以将其映射到一个1到10000000的数组中。

8bit是1byte,1024byte是1kb,1024kb是1mb

所以10000000个bit占用的空间为10000000/8/1024/1024mb大概为1mb多些,

这对于现在大家动不动几G的内存来说,完全是小菜一碟。

2. 2-Bitmap实现

在2.5亿个整数中找出不重复的整数,内存不足以容纳这2.5亿个整数。*/

每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义
    #include<stdio.h>  
    #include<memory.h>  
    //用char数组存储2-Bitmap,不用考虑大小端内存的问题  
    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

……

|00000000|

        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

如7 i= ,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;  
    }  


除了用2-Bitmap来计数标记以外,也可以用两个1-Bitmap来实现(如果考虑正负数的情况,就四个1-Bitmap)

### C语言中Bitmap数据结构的实现方法与代码示例 在C语言中,Bitmap(位图)是一种高效的数据结构,用于存储操作大量的布尔型数据。其核心思想是使用每一位来表示一种状态,通常用于需要快速查找、插入删除的应用场景[^2]。 以下是一个简单的Bitmap实现示例,展示了如何定义、初始化以及操作Bitmap数据结构: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define BITMAP_SIZE 1024 // 定义Bitmap的大小为1024位 // 定义Bitmap结构体 typedef struct { unsigned char *bits; // 使用unsigned char数组存储位 int size; // Bitmap的大小(以位为单位) } Bitmap; // 初始化Bitmap void bitmap_init(Bitmap *bitmap, int size) { bitmap->size = size; bitmap->bits = (unsigned char *)malloc((size / 8) + 1); // 分配足够的字节空间 memset(bitmap->bits, 0, (size / 8) + 1); // 将所有位初始化为0 } // 设置某一位为1 void bitmap_set(Bitmap *bitmap, int pos) { if (pos >= 0 && pos < bitmap->size) { bitmap->bits[pos / 8] |= (1 << (pos % 8)); // 设置指定位置的位为1 } } // 清除某一位为0 void bitmap_clear(Bitmap *bitmap, int pos) { if (pos >= 0 && pos < bitmap->size) { bitmap->bits[pos / 8] &= ~(1 << (pos % 8)); // 清除指定位置的位为0 } } // 检查某一位是否为1 int bitmap_test(Bitmap *bitmap, int pos) { if (pos >= 0 && pos < bitmap->size) { return (bitmap->bits[pos / 8] & (1 << (pos % 8))) != 0; // 检查指定位置的位是否为1 } return 0; } // 销毁Bitmap void bitmap_destroy(Bitmap *bitmap) { free(bitmap->bits); // 释放分配的内存 } // 测试函数 int main() { Bitmap bitmap; bitmap_init(&bitmap, BITMAP_SIZE); // 设置某些位 bitmap_set(&bitmap, 5); bitmap_set(&bitmap, 10); bitmap_set(&bitmap, 15); // 检查某些位 printf("Bit 5 is %s\n", bitmap_test(&bitmap, 5) ? "set" : "cleared"); printf("Bit 10 is %s\n", bitmap_test(&bitmap, 10) ? "set" : "cleared"); printf("Bit 15 is %s\n", bitmap_test(&bitmap, 15) ? "set" : "cleared"); // 清除某些位 bitmap_clear(&bitmap, 10); // 再次检查 printf("After clearing, Bit 10 is %s\n", bitmap_test(&bitmap, 10) ? "set" : "cleared"); // 销毁Bitmap bitmap_destroy(&bitmap); return 0; } ``` 上述代码实现Bitmap的基本功能,包括初始化、设置位、清除位、测试位以及销毁Bitmap的操作。通过这种方式,可以有效地管理操作大规模的布尔型数据集合[^2]。 ### 注意事项 - Bitmap的大小应根据实际需求进行调整。 - 在操作Bitmap时,需要注意边界条件,避免越界访问。 - 使用完毕后,务必调用`bitmap_destroy`函数释放分配的内存,防止内存泄漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值