当前位置: 首页 > news >正文

数据结构——位图

位图概念

位图可以用来快速判断某个数在不在,它的本质也是一种哈希结构,不过位图更节省空间。位图是用比特位来存储数据的。

我们知道一个整形有32个比特位,我们可以用1个整形存储32个数据,如果我们要查找15这个数在不在,只用判定这个整形的第15个比特位是0还是1,是0,说明不在,是1说明在,如果我们要插入17,只用把这个整形的第17个比特位置设置为1即可。

因为C++没有一个比特的数据类型,因此这个地方我们用char或者int都是可以的,区别在于不同类型存储的比特位个数不同,这个地方我们就用整形了。

那如果我们要插入一个数是99呢?一个整形只有32个比特位呀,那我们搞一个整形数组即可。我们可以用99 / 32计算这个数在数组的哪一个下标,然后用99 % 32计算在该下标所对应整形的第几个比特位。99/32=3,因此对应下标为3的整形,99%32=3,因此映射到了该整形的第3个比特位。

相关位运算 

位图肯定是需要位运算的,因此我们需要知道一些位运算的知识。

将整形n的第x个比特位标记为1

比如说要把9的第3个比特位标记为1,我们先让9 | 1左移3位

用代码写出来就是 9 | (1 << 3) ,抽象一下就是 n | (1 << x)。

或运算的特性是有1就为1,全0才是0。1左移3位后,第3个比特位是1,然后与9进行或运算,由于或运算的特性,因此9的第3个比特位必定是1,然后9的其他位与0进行或运算,如果是1就是1,如果是0就是0,可以保证其它位不变,次数就把9的第三位变成了1。

将整形n的第x个比特位标记为0

比如说要把9的第4个比特位标记为0,我们可以让9与上1左移4位取反。

代码写出来是 n = n &(~(1 << x))

与运算的特性是全1为1,有0为0,1左移4位后第4个比特位是1,其它是0,取反后第4个比特位是0,其它位全是1,其它位全是1的情况下和9进行与运算,其它位不变,然而1的第4位是0,不管9的第4位是0还是1都是0,。

获取整形n的第x个比特位是0还是1

直接让n & (1 << x),如果结果是0该为就是0,否则是1。1左移x位,第x位为1,其它位全是0,和n进行与运算,其它位全都会变成0,如果n的第x位是1,那么结果就是大于1的,如果n的第x位是0,那么0 & 1结果是0。

位图

位图的底层我们可以直接用一个vector数组来实现,位图也是一种哈希,因此我们要提前给位图开好空间。并且位图是不可以动态扩容的,需要我们一次就把空间开好,当然也可以动态扩容,但是扩容之后可能会导致索引发生变化,还是很麻烦的,因此最后直接一次开好就行。

// 非类型模版参数
template <size_t N>
class bitset
{
public:
    // 构造函数
    bitset()
    {
        _bits.resize(N / 32 + 1, 0);
    }
 
private:
    vector<int> _bits; // 位图;
};

我们可以通过模版参数的方式来给位图开空间,模版参数传递这个位图需要存储的最大值,因为1个整形可以存32个数,因此我们实际上并不需要开N个空间,只需要N / 32 + 1个空间即可,因为有可能N不是32的倍数除不尽,因此要多开一个空间给那些余数。

设置位(插入)

当要插入一个数的时候,只需要计算出该位所在的整形以及所在的比特位,计算所在的整形直接 / 32即可,计算在哪个比特位 % 32即可,然后把该位设置为1即可。

    // 设置位
    void set(size_t x)
    {
        // 计算出在第i个整形的第j位
        int i = x / 32;
        int j = x % 32;
        _bit[i] |= (1 << j); // 将该位设置为1,不影响其它位
    }

清除位(删除)

当要把一个数从位图删除,同样计算出在哪个整形哪个比特位,然后将该位置0即可

    // 清除位
    void reset(size_t x)
    {
        // 计算出在第i个整形的第j位
        int i = x / 32;
        int j = x % 32;
        _bit[i] &= (~(1 << j)); // 将该位设置为0,不影响其它位
    }

获取位是0还是1(查找)

    // 获取位的状态
    bool test(size_t pos)
    {
        int i = pos / 32;
        int j = pos % 32;
        if(_bits[i] & (1 << j)) // 该位被设置
            return true;
        else
            return false;
    }

但是现在有一个问题,位图的确可以解决一个数存在不存在,但如果我这个数是负数呢?如果一个数是负数我们其实可以通过映射等方法将其转成一个整数在进行映射,但是用到的不多。

但是如果我们要快速查询一个字符串在不在呢?现在的位图是解决不了的,这就需要引入下一个数据结构叫做布隆过滤器,布隆过滤器可以快速判断字符串在不在,并且也是采用位图的形式。

相关文章:

  • Redis 源码分析-内部数据结构 robj
  • 帧中继+静态路由实验(大规模网络路由器技术)
  • DeepSeek开源周Day5压轴登场:3FS与Smallpond,能否终结AI数据瓶颈之争?
  • React 中 useState 的 基础使用
  • Windows 图形显示驱动开发-WDDM 3.2-自动显示切换(十二)
  • 民安智库:物业满意度调查的数据分析经验分享
  • 《宇宙》自我意识之局部宇宙,无垠星空之真实宇宙
  • Android+SpringBoot的老年人健康饮食小程序平台
  • 【react】快速上手基础教程
  • 《向华为学习:BEM战略解码》课程大纲
  • 消息队列学习-常用消息队列中间件的对比分析
  • 加载大数据时性能压力优化
  • phpstudy小皮面板下载安装及启动MySQL的报错解决
  • git 强推
  • python随机数如何赋值给变量
  • 信号和槽
  • 物联网智能项目实战:从概念到实现
  • 计算机组成与接口12
  • 蓝桥备赛(五)- string(下)
  • Java 连接 Redis 的两种方式
  • 呼伦贝尔网站建设维护/贵州seo技术培训
  • 庆阳市人大常委会网站建设/seo能干一辈子吗
  • 网站登录模版/发外链的论坛
  • 17网做网站/焊工培训内容
  • 网站建设结课总结/扬州百度关键词优化
  • 柳市做公司网站/平台推广渠道