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

数据结构——位图

位图概念

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

我们知道一个整形有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;
    }

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

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


http://www.kler.cn/a/565863.html

相关文章:

  • 使用自动化运维工具 Ansible 集中化管理服务器
  • 记录深度学习中有用的终端命令
  • java23种设计模式-责任链模式
  • 【VSCode】VSCode下载安装与配置极简描述
  • HTTP学习——————(四)TLS等加密算法
  • 力扣——最小路径和
  • [自然语言处理]pytorch概述--什么是张量(Tensor)和基本操作
  • 数字人口播:开启内容创作新时代,实时对话数字人源码环境,可OEM
  • Gin框架深度解剖:中间件的实现原理
  • PC 端连接安卓手机恢复各类数据:安装、操作步骤与实用指南
  • AWS成本优化完整方案:从基础配置到高阶策略
  • 大结构体接收后只读让其他线程可见的轻量级方法
  • 萌新学 Python 之 random 函数
  • 解决yarn run dev报错: TypeError: Cannot create property ‘-registry-npmmirror-com‘
  • 揭开人工智能中 Tokens 的神秘面纱
  • YOLOv8车牌关键点定位与矫正识别系统
  • 73.发布单文件 WPF例子 C#例子
  • Android Studio 新版本Gradle发布本地Maven仓库示例
  • DCDC60V电源ic,支持48V降压5V、36V降压5V,SL3037B替换TPS54362
  • 【Redis】Mac系统一键安装redis