【C++】位图(海量数据处理)
文章目录
- 抛出问题:引入位图
- 位图解决
- 位图的概念
- 位图的实现
- 结构
- 构造函数
- 设置位
- 清空位
- 判断这个数是否存在
- 反转位
- size与count
- 打印函数
- 位图的应用
抛出问题:引入位图
问题:给40亿个不重复的无符号整数,没排序,给一个无符号整数,如何快速判断这个数是否在这40亿个数中。
解题思路:
- 遍历,时间复杂度O(N);
- 先排序(O(NlogN)),再利用二分查找(logN)。
- 放到哈希表或者红黑树。
现在我们来分析一下上面的思路是否可行。首先我们要知道40亿个无符号整数占用多少空间:1G=1024MB=1024x2024KB=1024x1024x1024Byte,约等于10亿字节,所以40亿个无符号整数(一个整数需要占用4个字节)需要占用约16G的内存空间。
40亿个无符号整数需要16G的空间,那我们就只能采用归并排序了,但是二分查找算法没办法在文件中完成,所以思路1不适用。
如果放到哈希表或红黑树,我们首先要把文件中的数据加载到内存,可以采用分步加载,然后还要将这些数据插入到哈希表或红黑树中,构建完成后,再find数据。那还不如暴力查找,对吧。
综上,以上几种思路不适用的重要原因是:内存不足。
位图解决
数据是否在给定的整型数据中,结果无非两种,在或不在,那么我们就可以使用一个二进制比特位来代表数据是否存在,如果二进制比特位为1,代表存在,0代表不存在。往往我们可以将整数转换成char去存储,一个char等于1个字节=8个比特位,这样40亿个无符号整型就大概只需要0.5G的内存空间。比如:

位图的概念
位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的处理,通常是用来判断某个数据是否存在。
位图的实现
结构
- 采用字符数组
- 采用非类型模板参数,N表示要设置的bit位数
namespace zxn
{//模拟实现位图template<size_t N>class bitset{public://构造函数bitset();//设置位void set(size_t x);//清空位void reset(size_t x);//判断数据是否存在bool test(size_t x); //反转位void flip(size_t pos); //获取可以容纳的位的个数size_t size();//获取被设置位的个数size_t count();//打印函数void Print();private:vector<char> _bits; //位图};
}
构造函数
N是非类型模板参数,表示我们需要设置的bit位数,因为我们采用字符数组,存储的类型是char,char类型占一个字节,所以N/8+1表示我们需要的char类型空间。利用resize函数,开空间的同时将其初始化为0。
//构造函数
bitset()
{_bits.resize(N / 8 + 1, 0);
}
设置位
如何将数据对应的比特位设置为1(存在)?
这里注意区分左移<<,右移>>,和虚拟内存当中的低地址,高地址。
- 回顾大小端的概念
大端字节序:低位存在高地址
小端字节序:低位存在低地址

注意:读的时候是从低地址到高地址>
- 为什么采用左移位(观察虚拟内存地址)

void set(size_t x)
{//计算数据x映射的比特位在第i个char数组的位置size_t i = x / 8;//计算数据x映射的比特位在这个char的第j个比特位size_t j = x % 8;_bits[i] |= (1 << j);
}
清空位
reset函数的功能是将一个数据对应的比特位设置为不存在。
void reset(size_t x)
{//计算数据x映射的比特位在第i个char数组的位置size_t i = x / 8;//计算数据x映射的比特位在这个char的第j个比特位size_t j = x % 8;_bits[i] &= ~(1 << j);
}
判断这个数是否存在
test函数的功能是判断这个无符号正常是否在这40亿个不重复的数据中。如果这个数据对应的比特位状态为1,就说明这个数据存在,返回true。
bool test(size_t x)
{size_t i = x / 8;size_t j = x % 8;return _bits[i] & (1 << j);//或return (_bits[i]<<j)&1;
}
反转位
- 计算出数据对应的比特位位置。
- 将1左移j位与char中的第i个比特位进行异或运算。(相异为1,相同为0)
//反转位
void flip(size_t x)
{size_t i = x / 8;size_t j = x % 8;_bits[i] ^= (1 << j);//异或:相异为1,相同为0
}
size与count
//获取可以容纳的比特位个数
size_t size()
{return N;
}
获取位图中1的个数方法:
- 将原树n与n-1进行&与运算得到新的n;
- 判断n是否为0,若n不为0则循环进行第一步。
- 如此循环进行下去,直到n最终为0,该代码被执行了几次就代表二进制位中有多少个1。
原理:n&(n-1)该操作每进行一次就会消去二进制最右边的1。

//获取比特位为1的个数
size_t count()
{size_t count = 0;for (auto e : _bits){//e是char类型的while (e){e = e & (e - 1);count++;}}return count;//被设置位的个数,即位图中1的个数
}
打印函数
打印函数的功能是:遍历位图,打印每个比特位,在打印的过程中也可以统计位的个数。
void Print()
{int count = 0;size_t n = _bits.size();//便于获取数组的最后一个字符//先打印前n-1个charfor (size_t i = 0; i < n - 1; i++){for (size_t j = 0; j < 8; j++){if (_bits[i] & (1 << j)){cout << "1";}else{cout << "0";}count++;}}//在打印最后一个字符的前N%8位for (size_t j = 0; j < N % 8; j++){if (_bits[n - 1] & (1 << j)){cout << "1";}else{cout << "0";}count++;}cout << " " << count << endl;
}
位图的应用
- 快速查找某个数据是否在一个集合中;
- 排序+去重;
- 求两个集合的交集,并集;
- 操作系统中磁盘块标记。
位图的优缺点:
- 优点:速度快,节省空间。
- 缺点:只能映射整型,其它类型,如浮点数,string等等不能存储映射。
问题一:给定100亿个整数,设计算法找到只出现一次的整数。
一个位图中的一个比特位只能表示两种状态,因此我们可以开辟两个位图,这两个位图的对应位置分别表示映射到该位置的整数的第一个位和第一个位。
可以用如下方式标记:
- 00表示不存在,没有出现过
- 01表示出现一次
- 10表示出现过一次以上

代码实现:复用bitset
template<size_t N>
class twobitset
{
public://设置位:00 表示出现0次,01表示只出现一次,10表示出现过一次以上void set(size_t x){//00 -> 01if (_bs1.test(x) == false && _bs2.test(x) == false){_bs2.set(x);}else if (_bs1.test(x) == false && _bs2.test(x) == true){//01 -> 10_bs1.set(x);_bs2.reset(x);}}void Print(){//遍历整个位图for (size_t i = 0; i < N; i++){//打印出只出现一次的整数,即第一位为0,第二位为1,01if (_bs2.test(i)){cout << i << endl;}}}
private:bitset<N> _bs1;bitset<N> _bs2;
};
void test_twobitset()
{int a[] = { 3, 45, 53, 32, 32, 43, 3, 2, 5, 2, 32, 55, 5, 53,43,9,8,7,8};twobitset<100> bs;//将数组a中的数据映射到位图中for (auto e : a){bs.set(e);}//打印出只出现一次的数据bs.Print();
}
注意:存储100亿个整数大概需要40G的内存空间,因此数据肯定是存储在文件中的;为了能映射所有整数,位图的大小必须开辟2^32位,即4294967295,因此开辟一个位图大概需要0.5G的内存空间,两个位图就要1G的内存空间,所以代码选择在堆区开辟空间,若是在栈区开辟会导致栈溢出问题。
问题二:给两个文件,分别有100亿个整数,我们只要1G内存,如何找到两个文件的交集。
思路一:
1.依次读取第一个文件的值,读到内存的一个位图中,再读取看一个文件,判断在不在第一个位图中,在就是交集,这个方法大约需要0.5G的内存,但是存在一个问题,就是找出的交集存在重复的值,我们还需要对其进行去重才可以。
2.改进方法:每次找到交集的值,都将第一个位图对应的值设置为0,这样就可以解决找到的交集有重复值的问题。
思路二:
1.依次读取文件1的数据映射到位图1;
2.依次读取文件2的数据映射到位图2;
3.将位图1和位图2的数据进行与&&操作,结果为1的就是交集。
问题三:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数。
这道题目的思路和题目1是一样的,我们可以用以下四种二进制表示四种状态:
- 00 出现0次
- 01 出现1次
- 10 出现2次
- 11 出现2次以上
#include <iostream>
#include <vector>
#include <bitset>
using namespace std;int main()
{int a[] = { 3, 45, 53, 32, 32, 43, 3, 2, 5, 2, 32, 55, 5, 53,43,9,8,7,8,55};//在堆上申请空间bitset<4294967295>* bs1 = new bitset<4294967295>;bitset<4294967295>* bs2 = new bitset<4294967295>;for (auto e : a){if (!bs1->test(e) && !bs2->test(e)) //00->01{bs2->set(e);}else if (!bs1->test(e) && bs2->test(e)) //01->10{bs1->set(e);bs2->reset(e);}else if (bs1->test(e) && !bs2->test(e)) //10->11{bs2->set(e);}}for (size_t i = 0; i < 4294967295; i++){if ((!bs1->test(i) && bs2->test(i)) || (bs1->test(i) && !bs2->test(i))) //01或10cout << i << endl;}return 0;
}相关文章:
【C++】位图(海量数据处理)
文章目录 抛出问题:引入位图位图解决 位图的概念位图的实现结构构造函数设置位清空位判断这个数是否存在反转位size与count打印函数 位图的应用 抛出问题:引入位图 问题:给40亿个不重复的无符号整数,没排序,给一个无符号整数,如何…...
外包干了五年,废了...
先说一下自己的情况。大专生,17年通过校招进入湖南某软件公司,干了接近5年的测试点点点,今年年上旬,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了五年的点工…...
请问你如何理解以下的歌词“unravel - TK from 凛冽时雨 (TK from 凛として時雨)为什么很多人说崖山海战以后无中国
目录 请问你如何理解以下的歌词“unravel - TK from 凛冽时雨 (TK from 凛として時雨) 为什么很多人说崖山海战以后无中国 请问你如何理解以下的歌词“unravel - TK from 凛冽时雨 (TK from 凛として時雨) 以下是我对《unravel - TK from 凛冽时雨》这首歌词的理解࿱…...
从8连挂到面面offer,我只用了一个月,面试25K测试岗血泪经验分享给你
直到如今,我才敢把这段经历分享出来,毕竟一个多月前,我是经历了面试八连挂的人。作为一只骄傲的软件测试工程师,恨不得找一块豆腐撞死。但是在闭关修炼了一个多月之后,重新出来面试,面试了五家公司…...
计算机操作系统(慕课版)第二章课后题答案
一、简答题 (1)什么是前趋图?试画出下面四条语句的前趋图. S1:axy; S2:bz1; S3:ca-b; S4:wc1; 答:前趋图(Precedence Graph)是一个有向无循环图,…...
【离散数学】置换群和伯恩赛德定理编程题
1:置换的轮换表示 给出一个置换,写出该置换的轮换表示。比如 (1 2 3 4 5 6 7 8 9) (3 1 6 2 9 7 8 4 5) 表示为(1 3 6 7 8 4 2)(5 9) 输入: 置换后的序列 输出: 不相杂的轮换乘积,每行表示一个轮换(轮换的起…...
【自然语言处理】 - 作业2: seq2seq模型机器翻译
课程链接: 清华大学驭风计划 代码仓库:Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的,其分为四门课,包括: 机器学习(张敏教授) , 深度学习(胡晓林教授), 计算…...
随身WIFI折腾日记(四)---拓展USB接口读取U盘内容
五、USB行为控制 随身WIFI对外交互的接口只有WIFI和USB接口。如果要想接入其他硬件设备,拓展USB接口至关重要,对于USB接口的控制,参考如下链接: openstick项目官方教程:控制usb行为 HandsomeMod/gc: A Simple Tool To Control Usb Gadget …...
【C++初阶】类与对象(中)之取地址及const取地址操作符重载(了解即可)
👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:C航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞…...
代驾公司如何管理司机
在这个几乎人人都能学车,人人都能开车的时代,代驾职业也越来越专业化和正规化。因此,想要成为一名优秀的代驾司机,一定得有过人之处,对于代驾公司来说,如何管理司机也是尤为的重要。 对于代驾公司来说&…...
面了一个5年经验的测试工程师,自动化都不会也敢喊了16k,我也是醉了····
在深圳这家金融公司也待了几年,被别人面试过也面试过别人,大大小小的事情也见识不少,今天又是团面的一天, 一百多个人都聚集在一起,因为公司最近在谈项目出来面试就2个人,无奈又被叫到面试房间。 整个过程…...
ChatGPT:你真的了解网络安全吗?浅谈攻击防御进行时之网络安全新定义
ChatGPT:你真的了解网络安全吗?浅谈网络安全攻击防御进行时 网络安全新定义总结 ChatGPT(全名:Chat Generative Pre-trained Transformer),美国OpenAI 研发的聊天机器人程序,是人工智能技术驱动…...
LeetCode_DFS_困难_1377.T 秒后青蛙的位置
目录 1.题目2.思路3.代码实现(Java) 1.题目 给你一棵由 n 个顶点组成的无向树,顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下: 在一秒内,青蛙从它所在的当前顶点跳到另一个未访问过的顶点(如果它…...
第四十九天学习记录:C语言进阶:结构体
结构体 结构体的声明 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量 struct tag {member-list; }variable-list;问:C的new和C语言的结构体有什么异同? ChatAI答: C中的new是一个运算符ÿ…...
LeeCode [N字形变换]算法解析
关键字:数学归纳法 一、题目 将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下: P A H N A P L S I I G Y I R …...
CPU性能提升:流水线
一条指令的执行一般要经过取指令,翻译指令,执行指令3个基本流程。CPU内部的电路分为不同的单元,取指但愿,译码单元,执行单元等。指令的执行也是按照流水线工序一步步执行的。如图2-34所示,我们假设每一个步…...
C语言指针初级
目录 一、什么是指针 二、指针和指针类型 三、野指针 1.野指针的成因: 2.如何规避野指针 四、指针运算 1.指针-整数 2. 指针之间的加减 五、二级指针 六、指针数组 一个男人,到底要走多少的路,才能成为一个真正的男人 本专栏适用于…...
C++的历史
C是一种广泛使用的编程语言。C于1983年由丹尼斯里奇(Dennis Ritchie)在贝尔实验室创造,它是C语言的扩展。C的设计初衷是为了提高代码的可重用性和可维护性。它允许开发人员使用面向对象编程(OOP)范例,这使得…...
保姆级别!!!--全网绝对教你会!!教你如何使用MQTTFX连接阿里云平台中的设备----下期告诉你如何创建!
本期需要下载的软件 MQttfx安装包,本人打包的-嵌入式文档类资源-CSDN文库 目录 第一步:建造阿里云设备 这个可以先忽略建造步骤,下期将提供步骤。 第二步:下载mqttfx软件 第三步:填写密钥信息进行连接 查看三元…...
Unexpected token ‘‘‘, “‘{“type“:““... is not valid JSON
尝试低代码schema解析JSON时报错,奇怪的是控制台解析正常,项目js执行JSON.parse()报错,简直无语了,,, 只能挨个检查了,首先温习了下JSON 的标准格式: JSON的合法符号:{(左大括号) }(右大括号) "(双引号) :(冒号) ,(逗号) [(左中括号) ](右中括号) JSON字符串:…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
