位图和布隆过滤器:位图

简介: 位图和布隆过滤器:位图

在《unordered_mapunordered_set》 中提到过:

哈希是一种思想,通过哈希函数将数据转化为一个或多个整型 —— 映射关系;通过这种映射关系,可以做到以 O(1) 的时间复杂度查找数据。

本文即将介绍的 位图布隆过滤器 就是两个非常典型的哈希思想的应用成果,可以在应对海量数据问题 且 做到极大程度节省空间的同时,快速判断 一个元素 是否在 位图 或 布隆过滤器 中

一、位图

1.1 位图的概念

在直接给出位图的概念之前,我们先温习几个常识:

  • 1 int == 4 byte
  • 1 byte == 8 bit ——> 1 int == 32 bit

也就是说,假设我们有 10 个位于 [0, 32) 的整数,仅需 1 个 int 就可以将这些数据标记(在保证数据范围的情况下,即使数据量更大一些也没问题)。

位图的概念:

各个比特位上的数据默认为 0 —— 不存在,遍历数据的过程中,将数据对应位置的 0 修改为 1 —— 存在;再判断某个整数是否存在时,仅须根据其对应位置上的状态(0 或 1)即可得出。

图中 “53 在 32 右边” 的情形并不绝对,与机器的大小端有关。无论你的设备是大端机还是小端机,“1 << 21” —— 左移 都能保证把 “1” 往数据高位移动

进一步延伸,面对这样一个场景:

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。

试图通过 排序 + 二分 的办法解决,显然不靠谱 —— 仅存下 40 亿个整数大约需要 16 GB 内存

面对海量整型数据,判断某个整数存在与否 的场景下,位图具有无可比拟的优势 —— 占用的空间小且能够快速查找

一个非常重要的问题:位图应该开多大的空间? 具体要开多大,不是由数据的个数决定,而是由数据的范围决定

代码:
template<size_t N> // 非类型模板参数
    class bitset 
    {
    public:
        bitset()
        {
            _bs.resize(N/32 + 1); // 开 (N/32 + 1) 个 int 类型空间
        }
        void set(size_t n) // 将 n 对应的位置状态修改为 1
        {
            size_t i = n / 32;
            size_t j = n % 32;
            _bs[i] |= (1 << j);
        }
        void reset(size_t n) // 将 n 对应的位置状态修改为 0
        {
            size_t i = n / 32;
            size_t j = n % 32;
            _bs[i] &= ~(1 << j);
        }
        bool test(size_t n) // 判断 n 是否存在
        {
            size_t i = n / 32;
            size_t j = n % 32;
            return _bs[i] & (1 << j);
        }
    private:
        vector<int> _bs;
    };

位图代码逻辑本身很简单,诸位读者要理解各个函数中位运算的经义。

PS: STL 库中 bitset 是在栈区上开空间,我们实现的位图在堆区上开空间。

1.2 切分思想

还是上面那个的场景(40 亿个不重复整数),我们进一步对可使用内存的大小进行限制 —— 只能使用 256 MB 。

这会带来一个结果:我们无法一次性把这么多整数存入位图 —— 40 亿个不重复整数大约 500 MB。

把这 40 亿个整数分成两个区间:[0, 2 ^ 31)[2 ^ 31, 2 ^ 32) 。(2 ^ 31 与 2 ^ 32 均为数学运算,C++ 中 ^ 为 异或)

先对 [0, 2 ^ 31) 范围内的整数进行 set() 和 test() ,处理完后将位图置空,再处理 [2 ^ 31, 2 ^ 32) 部分。

相关文章
EasyUI DataGrid 假分页
EasyUI DataGrid 假分页
231 0
|
存储 算法 关系型数据库
Mycat【Mycat分片技术(水平拆分-分表、ER表、全局表)】(五)-全面详解(学习总结---从入门到深化)
Mycat【Mycat分片技术(水平拆分-分表、ER表、全局表)】(五)-全面详解(学习总结---从入门到深化)
585 0
|
6月前
|
存储 人工智能 安全
拔俗AI临床大数据科研分析平台:让医学研究更智能、更高效
阿里云原生AI临床大数据科研平台,打通异构医疗数据壁垒,实现智能治理、可视化分析与多中心安全协作,助力医院科研提速增效,推动精准医疗发展。
1208 1
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
322 16
|
消息中间件 监控 前端开发
小巧快速 Kafka GUI 客户端推荐
想要查看Topic里的消息却找不到软件,想要查看或更新Broker、Topic配置,想要监控Broker服务器状态?试试下面的Kafka GUI工具——Kafka Assistant
1348 1
小巧快速 Kafka GUI 客户端推荐
|
运维 Java Nacos
Spring Cloud应用框架:Nacos作为服务注册中心和配置中心
Spring Cloud应用框架:Nacos作为服务注册中心和配置中心
|
存储 安全 JavaScript
文件上传漏洞(一)一句话木ma
文件上传漏洞(一)一句话木ma
|
缓存 算法 安全
被追着问UUID和自增ID做主键哪个好,为什么?
讨论了UUID和自增ID作为数据库主键的优缺点。UUID全局唯一,适合分布式系统,但存储空间大,不适合范围查询。自增ID存储空间节省,查询效率高,但分库分表困难,可预测性高。UUID版本包括基于时间戳(V1)、随机数(V4)以及基于名称空间的MD5(V3)和SHA1(V5)散列。
1653 1
被追着问UUID和自增ID做主键哪个好,为什么?
|
机器学习/深度学习
【机器学习】准确率、精确率、召回率、误报率、漏报率概念及公式
机器学习评估指标中的准确率、精确率、召回率、误报率和漏报率等概念,并给出了这些指标的计算公式。
4387 0
|
监控 Linux 数据处理
探秘Linux命令行神器:head命令
`head`命令是Linux命令行中的利器,用于显示文件开头的部分内容,常用于快速检查文件类型、结构或日志分析。默认显示前10行,可通过`-n`指定行数或`-c`指定字节数。结合管道与其他命令如`grep`、`sed`、`awk`可实现更多功能。注意在处理大文件和自动化脚本时,合理使用能提高效率。