【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字符串:…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...
手动给中文分词和 直接用神经网络RNN做有什么区别
手动分词和基于神经网络(如 RNN)的自动分词在原理、实现方式和效果上有显著差异,以下是核心对比: 1. 实现原理对比 对比维度手动分词(规则 / 词典驱动)神经网络 RNN 分词(数据驱动)…...