【C++篇】位图与布隆过滤器
目录
一,位图
1.1,位图的概念
1.2,位图的设计与实现
1.5,位图的应用举例
1.4,位图常用应用场景
二,布隆过滤器
2.1,定义:
2.2,布隆过滤器的实现
2.3, 应用场景
三,海量数据处理问题
3.1,10亿个整数求最大的前100个数
3.2,给两个文件,分别有100亿个query(查询字符串),我们只有1G内存,如何找到两个文件交集?
一,位图
1.1,位图的概念
位图是一种高效的数据结构,通过二进制位(0或1)的数组来高效存储和操作数据,常用于标记状态或处理大规模数据。
位图的优缺点:
优点:增删查改快,节省空间
缺点:只适用于整形
核心特性
-
空间高效:每个元素仅占1 bit,适合处理海量数据(如去重、统计)。
-
快速操作:支持位运算(与、或、异或等)进行高效查询和修改。
1.2,位图的设计与实现
位图本质是一个直接定址法的哈希表,每个整型值映射一个bit位。

核心接口:
对于一个 整形值x。计算x对应的bit位:i=x/32,j=i%32,得到x在第i个整形的第j个bit位。

对于一个 整形值x。要将它放入到数据中,只需将x对应的bit位由0置为1。

对于一个 整形值x,将它从数据中删除,只需将x对应的bit位由1置为0.

判断一个值x存不存在

代码:
//N空间大小,比特位
template<size_t N>
class bitset
{
public:bitset(){_bs.resize(N / 32 + 1);}//将x位置的bit值 置为1void set(const int& x){//第i个整型的第j个bit位size_t i = x / 32;size_t j = x % 32;_bs[i] |= (1 << j);}//删除x位置//将x位置的bit值 置为0void reset(const int& x){//第i个整型的第j个bit位size_t i = x / 32;size_t j = x % 32;_bs[i] &= (~(1 << j));}//判断x值在不在bool test(const int& x){//第i个整型的第j个bit位size_t i = x / 32;size_t j = x % 32;return _bs[i] & (1 << j);}
private:std::vector<int> _bs;
};
1.5,位图的应用举例
(1) 给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中。
40亿数据量太大,如果将40亿个int数据变量完全存储到内存中 可不得了,可以采用40亿个位来存储这些数据的状态。
首先遍历这40亿个数,在位图中将对应的位置为1,再对于给出的数,进行判断即可。
(2) 在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。
使用2个位图,每个数分配2个位图,用这两个位图来表示存储状态,00表示不存在,01表示出现一次,10表示多次,11无意义
代码示例:
template<size_t N>
class twobitset
{
public:
//添加x
void set(const int& x)
{
bool bit1 = bs1.test(x);
bool bit2 = bs2.test(x);
//出现0次->出现1次
if (!bit1 && !bit2)//00->01
{
bs2.set(x);
}
//出现1次->出现2次
else if (!bit1 && bit2)//01-> 10
{
bs1.set(x);
bs2.reset(x);
}
//出现2次->出现多次
else if (bit1 && !bit2)//10 ->11
{
bs2.set(x);
}
}
//获取x的出现次数
int getcount(const int& x)
{
bool bit1 = bs1.test(x);
bool bit2 = bs2.test(x);if (!bit1 && !bit2)//00
{
return 0;
}
else if (!bit1 && bit2)//01
{
return 1;
}
else if (bit1 && !bit2)//10
{
return 2;
}
else
{
return 3;
}
}
private:
bitset<N> bs1;
bitset<N> bs2;
};
1.4,位图常用应用场景
-
去重与存在性检查:
例如,统计10亿用户中哪些已注册,仅需约120MB内存(109÷8≈125MB109÷8≈125MB)。 -
布隆过滤器(Bloom Filter):
利用多个哈希函数和位图实现概率型数据存在性判断。 -
数据库索引:
快速筛选满足条件的记录(如性别为“男”的用户)。 -
内存管理:
操作系统用位图标记内存页的分配状态。
二,布隆过滤器
2.1,定义:
有一些场景,由大量数据需要判断是否存在,而这些数据不是整形,比如string,就不能使用位图了,这些场景就需要布隆过滤器来解决。利用多个哈希函数和位图实现,哈希函数内容见上篇文章【哈希表】。
核心原理
-
位数组(Bit Array):长度为 m 的二进制数组,初始全为0。
-
哈希函数集合:k个独立的哈希函数,每个函数将元素映射到位数组的某个位置。
以string类型为例:

而这种冲突是无法避免的,因为位图中只存储了状态,即0或1,无法改变。所以我们只能做到降低冲突概率,对于一个字符串,让它映射到多个位置上。经过k个哈希函数的转化,映射到k个位置,将这k位置都置为1。在查找时也是如此,经过k个哈希函数,k个位置都为1,才能说明该数据存在,否则就是与其他位置存在冲突,导致几个位置位1,几个位置为0,说明该数据不存在。

布隆过滤器优缺点:

2.2,布隆过滤器的实现
下图中 :
k代表哈希函数的个数
m为布隆过滤器的大小
n为插入的元素个数。

通过观察误判率的公式可得:在k一定的情况下,当n增加时,误判率增加,当m增加时,误判率越小。也就是哈希函数一定的情况下,插入元素越多时,误判率增加,布隆过滤器长度越长时,误判率减小。令X=m/n,可得,X越大,误判率越小。
//哈希函数
struct HashFuncBKDR
{// @detail 本 算法由于在Brian Kernighan与Dennis Ritchie的《The CProgramming Language》// 一书被展示而得 名,是一种简单快捷的hash算法,也是Java目前采用的字符串的Hash算法累乘因子为31。size_t operator()(const std::string& s){size_t hash = 0;for (auto ch : s){hash *= 31;hash += ch;}return hash;}
};
struct HashFuncAP
{// 由Arash Partow发明的一种hash算法。 size_t operator()(const std::string& s){size_t hash = 0;for (size_t i = 0; i < s.size(); i++){if ((i & 1) == 0) // 偶数位字符{hash ^= ((hash << 7) ^ (s[i]) ^ (hash >> 3));}else // 奇数位字符{hash ^= (~((hash << 11) ^ (s[i]) ^ (hash >> 5)));}}return hash;}
};
struct HashFuncDJB
{// 由Daniel J. Bernstein教授发明的一种hash算法。 size_t operator()(const std::string& s){size_t hash = 5381;for (auto ch : s){hash = hash * 33 ^ ch;}return hash;}
};//布隆过滤器
//M布隆过滤器的长度
//N插入元素个数
//X=M/N 越大,误判率越小
template<size_t N,size_t X=5,class k=string,class Hash1= HashFuncBKDR,class Hash2= HashFuncAP,class Hash3= HashFuncDJB>
class BloomFilter
{
public:void set(const k& key){size_t hash1 = Hash1()(key) % M;size_t hash2 = Hash2()(key) % M;size_t hash3 = Hash3()(key) % M;_bs.set(hash1);_bs.set(hash2);_bs.set(hash3);}//可能存在误判bool test(const k& key){//只要一个位置为0,就不存在size_t hash1 = Hash1()(key) % M;if (_bs.test(hash1) == 0)return false;size_t hash2 = Hash2()(key) % M;if (_bs.test(hash2) == 0)return false;size_t hash3 = Hash3()(key) % M;if (_bs.test(hash3) == 0)return false;return true;}
private:static const int M = N * X;bitset<M> _bs;
};
2.3, 应用场景
-
缓存穿透防护:
在分布式缓存系统中,布隆过滤器可以⽤来解决缓存穿透的问题。缓存穿透是指恶意用户请求⼀个不 存在的数据,导致请求直接访问数据库,造成数据库压力过⼤。布隆过滤器可以先判断请求的数据是 否存在于布隆过滤器中,如果不存在,直接返回不存在,避免对数据库的无效查询。 -
爬虫去重:
在爬虫系统中,为了避免重复爬取相同的URL,可以使⽤布隆过滤器来进行URL去重。爬取到的URL可 以通过布隆过滤器进行判断,已经存在的URL则可以直接忽略,避免重复的网络请求和数据处理。 -
对数据库查询提效:
在数据库中,布隆过滤器可以用来加速查询操作。例如:一个app要快速判断一个电话号码是否注册 过,可以使用布隆过滤器来判断一个用户电话号码是否存在于表中,如果不存在,可以直接返回不存 在,避免对数据库进行无用的查询操作。如果在,再去数据库查询进行二次确认。 -
垃圾邮件过滤:
在垃圾邮件过滤系统中,布隆过滤器可以用来判断邮件是否是垃圾邮件。系统可以将已知的垃圾邮件 的特征信息存储在布隆过滤器中,当新的邮件到达时,可以通过布隆过滤器快速判断是否为垃圾邮件,从而提高过滤的效率。
布隆过滤器通过牺牲一定的准确性,在海量数据去重、快速过滤等场景中展现了不可替代的优势,是分布式系统和大数据处理的基石技术之一。
三,海量数据处理问题
3.1,10亿个整数求最大的前100个数
本题是topk问题,用堆解决,建一个100个数的小堆,让这10亿个整数分别与堆顶元素比较,如果大于堆顶元素,就交换,再调整堆。最后最大的前100个就保存在小堆中。
3.2,给两个文件,分别有100亿个query(查询字符串),我们只有1G内存,如何找到两个文件交集?
解法一:使用布隆过滤器存储文件1,再遍历文件2,看布隆过滤器中是否存在,存在就是交集。
解法二:
哈希切分,首先内存的访问速度远大于硬盘,大文件放到内存搞不定,那么我们可以考虑切分为
文件,再放进内存处理。
本质是相同的query在哈希切分过程中,一定进入的同一个小文件Ai和Bi,不可能出现A中的的 query进入Ai,但是B中的相同query进入了和Bj的情况,所以对Ai和Bi进行求交集即可,不需要Ai 和Bj求交集。

哈希切分的问题就是每个⼩⽂件不是均匀切分的,可能会导致某个小文件很大内存放不下。我们细 细分析⼀下某个小文件很⼤有两种情况:1.这个小文件中⼤部分是同一个query。2.这个小文件是 有很多的不同query构成,本质是这些query冲突了。针对情况1,其实放到内存的set中是可以放 下的,因为set是去重的。针对情况2,需要换个哈希函数继续二次哈希切分。所以我们遇到大 于1G小文件,可以继续读到set中找交集,若set.insert时抛出了异常(set插⼊数据抛异常只可能是 申请内存失败了,不会有其他情况),那么就说明内存放不下是情况2,换个哈希函数进行二次哈希切分。
相关文章:
【C++篇】位图与布隆过滤器
目录 一,位图 1.1,位图的概念 1.2,位图的设计与实现 1.5,位图的应用举例 1.4,位图常用应用场景 二,布隆过滤器 2.1,定义: 2.2,布隆过滤器的实现 2.3, 应…...
[EAI-026] DeepSeek-VL2 技术报告解读
Paper Card 论文标题:DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding 论文作者:Zhiyu Wu, Xiaokang Chen, Zizheng Pan, Xingchao Liu, Wen Liu, Damai Dai, Huazuo Gao, Yiyang Ma, Chengyue Wu, Bin…...
CV报错与模型推理注意
错误1: error: OpenCV(4.10.0) :-1: error: (-5:Bad argument) in function warpAffine > Overload resolution failed: > - Cant parse dsize. Sequence item with index 0 has a wrong type > - Cant parse dsize. Sequence item with index 0 has a …...
如何解决云台重力补偿?
如何解决云台重力补偿? 最近在调试步兵云台的时候,由于枪管、图传、摄像头等重力的原因,pitch轴的参数尤其难以调整,又不想抬升和降低使用两套不同的参数,所以使用了重力补偿,效果也是比较理想的,于是整理为一篇文章记录一下 一、问题根源:枪管重力在“搞事情” 想象…...
Java 23新特性
文章目录 Java 23新特性一、引言二、Markdown文档注释(JEP 467)示例 三、ZGC:默认的分代模式(JEP 474)1. 为什么要引入分代模式2. 使用分代模式的优势3. 如何启用分代模式 四、隐式声明的类和实例主方法(JE…...
二叉树--链式存储
1我们之前学了二叉树的顺序存储(这种顺序存储的二叉树被称为堆),我们今天来学习一下二叉树的链式存储: 我们使用链表来表示一颗二叉树: ⽤链表来表⽰⼀棵⼆叉树,即⽤链来指⽰元素的逻辑关系。通常的⽅法是…...
OpenAI 实战进阶教程 - 第七节: 与数据库集成 - 生成 SQL 查询与优化
内容目标 学习如何使用 OpenAI 辅助生成和优化多表 SQL 查询了解如何获取数据库结构信息并与 OpenAI 结合使用 实操步骤 1. 创建 SQLite 数据库示例 创建数据库及表结构: import sqlite3# 连接 SQLite 数据库(如果不存在则创建) conn sq…...
基于直觉的理性思维入口:相提并论的三者 以“网络”为例
以下主要是 腾讯云 AI 代码助手的答问。 Q1、假设有且只有一个 能和主干网和 骨干网 相提并论的其它什么 “**网”,您觉得应该是什么 在考虑能与主干网和骨干网相提并论的“网”时,我们需要思考哪些网络在规模、重要性或功能上与这两者相当。主干网和骨…...
C++,vector:动态数组的原理、使用与极致优化
文章目录 引言一、vector 的核心原理1. 底层数据结构1.1 内存布局的三指针模型1.2 内存布局示意图 2. 动态扩容机制2.1 动态扩容过程示例 3. 关键结论4. 代码验证内存布局5. 总结 二、vector 的使用方法1. 基本操作2. 迭代器与范围遍历 三、vector 的注意事项1. 迭代器失效2. 性…...
bootstrap.yml文件未自动加载问题解决方案
在添加bootstrap.yml文件后,程序未自动扫描到,即图标是这样的: 查了一些资料,是缺少bootstrap相关依赖,虽然已经添加了spring-cloud-context依赖,但是这个依赖并未引入bootstrap依赖,可能是版本问题,需要手动引入 <dependency><groupId>org.springframework.cloud&…...
54【ip+端口+根目录通信】
上节课讲到,根目录起到定位作用,比如我们搭建一个php网站后,注册系统是由根目录的register.php文件执行,那么我们给这个根目录绑定域名https://127.0.0.1,当我们浏览器访问https://127.0.0.1/register.php时࿰…...
实现数组的扁平化
文章目录 1 实现数组的扁平化1.1 递归1.2 reduce1.3 扩展运算符1.4 split和toString1.5 flat1.6 正则表达式和JSON 1 实现数组的扁平化 1.1 递归 通过循环递归的方式,遍历数组的每一项,如果该项还是一个数组,那么就继续递归遍历,…...
blender 相机参数
目录 设置相机参数: 3. 设置相机参数示例 4. 相机透视与正交 5. 额外的高级设置 设置相机参数: 设置渲染器: 外参转换函数 转换测试代码: 获取blender渲染外参: 设置相机参数: 3. 设置相机参数示…...
物联网 STM32【源代码形式-ESP8266透传】连接OneNet IOT从云产品开发到底层MQTT实现,APP控制 【保姆级零基础搭建】
一、MQTT介绍 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种基于发布/订阅模式的轻量级通讯协议,构建于TCP/IP协议之上。它最初由IBM在1999年发布,主要用于在硬件性能受限和网络状况不佳的情…...
软考高项笔记 信息技术及其发展
信息技术及其发展 ❝ 信息系统项目管理师第二章第一节 1. 网络标准协议的定义 网络协议是为计算机网络中进行数据交换而建立的规则、标准或约定的集合。网络协议由三个要素组成,分别是语义、语法和时序。 语义:解释控制信息每个部分的含义,它…...
计算机网络 性能指标相关
目录 吞吐量 时延 时延带宽积 往返时延RTT 利用率 吞吐量 时延 时延带宽积 往返时延RTT 利用率...
【初/高中生讲机器学习】0. 本专栏 “食用” 指南——写在一周年之际⭐
创建时间:2025-01-27 首发时间:2025-01-29 最后编辑时间:2025-01-29 作者:Geeker_LStar 你好呀~这里是 Geeker_LStar 的人工智能学习专栏,很高兴遇见你~ 我是 Geeker_LStar,一名高一学生,热爱计…...
[SAP ABAP] 性能优化
1.数据库编程OPEN SQL方面优化 1.避免使用SELECT *,只查询需要的字段即可 尽量使用SELECT f1 f2 ... (具体字段) 来代替 SELECT * 写法 2. 如果确定只查询一条数据时,使用 SELECT SINGLE... 或者是 SELECT ...UP TO 1 ROWS ... 使用语法 UP TO n ROWS 来…...
软件测试02----用例设计方法
今天目标 1.能对穷举场景设计测试点 2.能对限定边界规则设计测试点 3.能对多条件依赖关系进行设计测试点 4.能对项目业务进行设计测试点 一、解决穷举场景 重点:使用等价类划分法 1.1等价类划分法 重点:有效等价和单个无效等价各取1个即可。 步骤&#…...
Nginx 日志分析与监控
一、引言 在当今互联网时代,Web 服务的稳定运行和高效性能是至关重要的。Nginx 作为一款高性能的 HTTP 和反向代理服务器,以其出色的稳定性、高效性和丰富的功能,被广泛应用于各类 Web 项目中,成为了 Web 服务架构中不可或缺的一…...
冷启动+强化学习:DeepSeek-R1 的原理详解——无需监督数据的推理能力进化之路
本文基于 DeepSeek 官方论文进行分析,论文地址为:https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf 有不足之处欢迎评论区交流 原文翻译 在阅读和理解一篇复杂的技术论文时,逐字翻译是一个重要的步骤。它不仅能帮助我们准确把握作者的原意,还能为后续…...
笔试-二进制
应用题 将符合区间[l,r]内的十进制整数转换为二进制表示,请问不包含“101”的整数个数是多少? 实现 l int(input("请输入下限l,其值大于等于1:")) r int(input("请输入上限r,其值大于等于l&#x…...
014-STM32单片机实现矩阵薄膜键盘设计
1.功能说明 本设计主要是利用STM32驱动矩阵薄膜键盘,当按下按键后OLED显示屏上会对应显示当前的按键键值,可以将此设计扩展做成电子秤、超市收银机、计算器等需要多个按键操作的单片机应用。 2.硬件接线 模块管脚STM32单片机管脚矩阵键盘行1PA0矩阵键盘…...
Spring Boot 2 快速教程:WebFlux处理流程(五)
WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤: 第一步:发起请求到前端控制器(DispatcherServlet) 第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找) 匹配条件包括…...
unity学习25:用 transform 进行旋转和移动,简单的太阳地球月亮模型,以及父子级关系
目录 备注内容 1游戏物体的父子级关系 1.1 父子物体 1.2 坐标关系 1.3 父子物体实际是用 每个gameobject的tranform来关联的 2 获取gameObject的静态数据 2.1 具体命令 2.2 具体代码 2.3 输出结果 3 获取gameObject 的方向 3.1 游戏里默认的3个方向 3.2 获取方向代…...
CH340G上传程序到ESP8266-01(S)模块
文章目录 概要ESP8266模块外形尺寸模块原理图模块引脚功能 CH340G模块外形及其引脚模块引脚功能USB TO TTL引脚 程序上传接线Arduino IDE 安装ESP8266开发板Arduino IDE 开发板上传失败上传成功 正常工作 概要 使用USB TO TTL(CH340G)将Arduino将程序上传…...
Python量化交易助手:xtquant的安装与应用
Python量化交易助手:xtquant的安装与应用 技术背景和应用场景 在量化交易领域,Python因其强大的库支持和灵活性成为了许多开发者的首选语言。其中,xtquant 是迅投官方开发的一个Python包,专门用于与miniqmt通信,实现…...
上海路网道路 水系铁路绿色住宅地工业用地面图层shp格式arcgis无偏移坐标2023年
标题和描述中提到的资源是关于2023年上海市地理信息数据的集合,主要包含道路、水系、铁路、绿色住宅区以及工业用地的图层数据,这些数据以Shapefile(shp)格式存储,并且是适用于ArcGIS软件的无偏移坐标系统。这个压缩包…...
touch 命令与动态链接器漏洞分析:基于库文件劫持的提权攻击
touch 命令在 Linux 系统中,通常用于修改文件的访问时间(atime)和修改时间(mtime),或者在文件不存在时创建一个空文件。若 touch 命令被赋予 SUID(Set User ID)权限,它将以文件所有者(通常是 root )的身份执行。这为潜在的提权攻击提供了切入点,攻击者可利用此特性…...
DeepSeekMoE:迈向混合专家语言模型的终极专业化
一、结论写在前面 论文提出了MoE语言模型的DeepSeekMoE架构,目的是实现终极的专家专业化(expert specialization)。通过细粒度的专家分割和共享专家隔离,DeepSeekMoE相比主流的MoE架构实现了显著更高的专家专业化和性能。从较小的2B参数规模开始&#x…...
