【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字符串:…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...