位图

位图(Bit Map)是一个数组的每一个数据的每一个二进制位表示一个数据,0表示数据不存在,1表示数据存在。

不好理解的话,由下面这道题来引出位图的使用:
给出40亿个不重复的无符号整数,没排过序,给出一个无符号整数,如何快速判断一个数是否在这40亿个数中?

解题思路:

  1. 首先没由给出数的范围,只说了无符号整数,所以就要考虑到0到最大整数42亿的整个区间的所有数。
  2. 所有数据没有排过序,故而不能使用类似二分查找这样快速的方法去判断在不在。
  3. 开一个可以容纳所有整数的数组,42亿个字节差不多就是4个G的内存,一个整型占4个字节,一共就要16G的内存来存放这些数,16G内存,作为面试题,这个思路字节PASS掉吧。
  4. 既然一个整型代表一个数太过浪费,那就可以考虑用一个bite来表示一个数,一个整型4个字节,一个字节8个位,这样下来,一个整型就可以代表32个数,这样算下来,42亿只需要500M的空间,想想好像可以解决了。

基于这样的思想,看如下图示:
这里写图片描述

将每个存在的数对应的比特位都置为1,则可以在O(1)时间复杂度内判断一个数存在还是不存在。

上面就是位图的具体应用,即判断在还是不在,在最大局限就是只能对整数进行操作,如果是判断字符串呢?后续会讲到其他数据结构。

那么基于以上思想写出位图代码:

class BitMap
{
public:
    BitMap(size_t range)
    {
        //一共开多少个字节,余数的原因,所以+1
        _bits.resize(range >> 3 + 1,0);
    }

    //将一个数添加进位图
    void Set(size_t value)
    {
        //计算出位于哪个字节
        size_t index = (value>>3);//尽量以移位操作代替乘除操作
        //计算出具体在该字节哪个位
        size_t num = value % 8;

        //将该位置为1
        _bits[index] |= (1 << num);
    }

    //将一个数从位图中去除
    void ReSet(size_t value)
    {
        size_t index = (value >> 3);
        size_t num = value % 8;

        _bits[index] &= (~(1 << num));
    }

    //判断一个数是否在位图中存在
    bool Test(size_t value)
    {
        size_t index = (value >> 3);
        size_t num = value % 8;

        return _bits[index] &(1 << num);
    }
protected:
    vector<char> _bits;
};

位图的扩展
如果将上面那道题目改成,在40亿无符号整数中找出只出现一次的数。

如果是这样的话,那么一位是0或者1,只能表示两种状态,已经解决不了目前这种情况了,因为判断一个是否只出现一次对应三种状态:出现0次,出现一次,出现多次。
两个位有00 01 10 11四种状态,可以用00表示改数不存在,01表示只出现一次,用10或者11表示多次就可以了。

位图的应用:

  1. 可以对整数进行排序,对应位置位1,最后遍历整个位图就可以将一组整型排序。
  2. linux下信号的block表,pending表。
  3. 操作系统中,对pid号的管理使用位图,这样操作系统就可以快速判断哪个pid尚未分配出去,从而分配给新的进程一个pid号。
  4. linux下文件权限的保存

总之只要是判断在或者不在的情况,都可以使用位图来解决,但是位图的局限性就在于只能针对整型,对于字符串位图无法解决。

如果想要判断一个字符串是否在一大堆字符串是否存在,我们可以采用另一种数据结构,即布隆过滤器!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值