位图 及 代码实现

QA 先抛出一个问题: 

        如何对一个存储了1亿个整数范围为1~10亿)的 文件中的  数据 进行排序

下面将介绍一种 特殊的哈希表 —— 位图 

一、位图 的 基本思想 

       一句话概括就是:使用一种哈希算法,联合 数组下标 和 数组元素二进制位的数值  来 表示一个数值。 

        申请一个长度M(假设 1亿)的bool类型的数组 array,初始化数组的每个值为false(即array[0]~array[M] 都为 false)。 

        将N个整数作为数组下标对应的数组元素值设置为true。 (假设整数6包含在这N个数值中,则下标为 6的数组元素值设置为true)。

        当要查询某个整数K是否在这N个整数中,只需要将对应的数组值array[K]取出,查看是否等于true。 如果array[K] = false,那么说明这 N 个数中,不包含整数K ; 如果array[K] = true,那么说明这 N 个数中,包含整数K。      

基本的思想和原理,如上所描述。 对于一个char 数组元素 的 二进制位 示意图如下:

        布尔值类型数值,只有true和false两个值,只需要一个二进制位 (bit) 就可以表示。  在C++中布尔类型占用 一个字节(8bit)大小  的内存空间,对于位图有更节省空间的存储方式

        可以用一个char类型数据 表示一个长度是8(8位)的位图,同理用char类型的 a[n] 数值表示长度是  n*8 的位图。   

        获取 位图中的数据时,先用 数据除 8 ,得到这个数据存储在哪个数组元素中;     

         再用 数据与 8 求余,得到数组存储在这个数组元素中的哪一个二进制位上。

例如:

        对于53,与8相除得到 6.则 数据的位图 存储在数组元素 a[6] 中;再与8求余,得到5,则数据的位图 存储在 a[6] 的第5位二进制上。

二、代码实现如下:

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

class BitMap
{
public:
    BitMap(int nbit)
    {
        this->numbit = nbit;
        this->bt = vector<char> (nbit/8 +1,0);
    }

    void set(int value)
    {
        if (value > numbit) return;
        int byteindex = value / 8;
        int bitindex = value % 8;
        
        //将 1 左移 bitindex位,然后再与原来的数值 相 或
        bt[byteindex] |= (1 << bitindex);
    }

    bool get(int value)
    {
        if (value > numbit) return false;
        int byteindex = value / 8;
        int bitindex = value % 8;
        //将1 左移 bitindex位,然后再与原来的数值 相 与,获得 bitindex位置的布尔值 
        return (bt[byteindex] & (1 << bitindex)) != 0;
    }

private:
    vector<char> bt;
    int numbit;
};

int main()
{
    BitMap myBitMap = BitMap(17);
    myBitMap.set(3);
    myBitMap.set(6);
    myBitMap.set(9);
    myBitMap.set(23);
    myBitMap.set(11);

     
    cout << "查找数值3 存在吗?"  << myBitMap.get(3) << endl;
    cout << "查找数值6 存在吗?"  << myBitMap.get(6) << endl;
    cout << "查找数值10 存在吗?" << myBitMap.get(10)<< endl;
    cout << "查找数值27 存在吗?" << myBitMap.get(27)<< endl;


    return 0;
}

执行的结果如下:

位图是通过数组下标来定位数据,所以访问效率非常高,也就是说 查询效率非常高。 

对于在1000万个整数查找数据这个问题,   如果使用哈希表来存储这100万个数据,那么大约需要40MB的内存空间。  如果使用位图来存储着1000万个数据, 如果将数字的范围设置为1 ~ 1亿,而只需要 1亿个二进制位,也就是说 12MB左右的内存空间就足够了。

位图只用一个二进制位就能表示一个数字,在数组范围不大的情况下,相对于哈希表,位图这种数据结构非常节省内存。

三、回答刚开始提的问题:

如何对一个存储了1亿个整数范围为1~10亿)的 文件中的  数据 进行排序

假设如果不需要统计重复数字的次数,可以申请一个大小是10亿的位图,只需要120MB左右的内存。 只需要根据位图中,输出二进制位 为 true的下标 即可,  从左到右输出,就是从小到大排序;从右向左输出,就是从大到小排序。(这样是一种解法 ,不过 内存消耗太大了,可以通过布隆过滤器优化的方案)

位图的数据所在范围不能太大 。如果数据的范围很大,比如1~10亿,那么位图占用的内存空间,相比哈希表的内存占用,要大。  为了解决这种内存占用,随着 数值范围 变大 增加的问题,就产生了 布隆过滤器 对位图进行改进和优化 。 

关于 布隆过滤器 的  原理介绍 和 解读,见另一篇博客,链接如下:

XXXXX (等待更新)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值