当前位置: 首页 > news >正文

【C++修炼之路】24.哈希应用--位图

在这里插入图片描述
每一个不曾起舞的日子都是对生命的辜负

哈希应用--位图

  • 哈希应用:位图
  • 一.提出问题
  • 二.位图概念
  • 三.位图代码
  • 四.位图应用
  • 五.经典问题

哈希应用:位图

一.提出问题

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

先考虑内存的问题:40亿个整数, 每个整数4字节,换算大约16G的空间,寻常的查找算法都是不可能完成的。因此引入位图

二.位图概念

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。

通过这种同样是哈希的思想,就可以极大的节省空间,整形范围在0~232-1,因此我们可以开232个比特位,换算下来只有512M的大小,通过直接映射就能够判断。


我们无法开这么大的数组,但我们采用的是bit位的标记,即值是几,就把第几个位标记成1。

那么如何去找呢?实际上我们把数组的元素类型规定为char(int也可以),这样就可以通过如下的方式去找任意一个数:x

  • x映射的值,在第几个char对象上:x/8

  • x映射的值,在这个char对象的第几个比特位:x%8

比特位顺序问题:

事实上,比特位的顺序与机器的大小端无关,仍是和地址一样从右到左:image-20230303193809130

因此在处理定位x在指定char的第几个比特位上时,就需要从右到左去查找。

三.位图代码

对于位图的功能,要有插入,删除,检测在不在三个功能,如果这样赋值:

  • size_t i = x / 8;
  • size_t j = x % 8;

插入就可以这样:_bits[i] |= (1 << j);

删除就可以这样:_bits[i] &= (~(1 << j));

测试这个值在不在就可以这样:return _bits[i] & (1 << j);

此外,一开始同样需要开辟指定大小的空间,因此构造函数中要写出来。

template<size_t N>
class cfy_set
{
public:void set(size_t x)//标记{size_t i = x / 8;size_t j = x % 8;_bits[i] |= (1 << j);}void reset(size_t x)//清除{_bits[i] &= (~(1 << j));}bool test(size_t x)//测试这个值在不在{size_t i = x / 8;size_t j = x % 8;return _bits[i] & (1 << j);}
private:vector<char> _bits;
};

对于测试这个值在不在的返回值,会发生整形提升,因为bool属于int类型,按照符号位的数值进行补位,但是对于逻辑来说不重要。

需要注意的是,由于是无符号数,事实上可以将x/8+1换成(x>>3)+ 1;由于>>的优先级低于+,所以需要加上括号。

测试:

void test_cfy_set()
{//cfy_set<100> cs1;//cfy_set<-1> cs2;//无符号最大数直接传-1,会转成最大数量cfy_set<0xffffffff> cs3;//同上cs3.set(10);cs3.set(10000);cs3.set(8888);cout << cs3.test(10) << endl;cout << cs3.test(10000) << endl;cout << cs3.test(8888) << endl;cout << cs3.test(8887) << endl;cout << cs3.test(9999) << endl;
}

image-20230303203136790


事实上,库中也有位图结构 bitset ,也可以直接通过库中的位图查找。

四.位图应用

一. 给定100亿个整数,设计算法找到只出现一次的整数?

对于此整数有三种状态:

  1. 出现0次
  2. 出现1次
  3. 出现一次以上

因此,我们可以通过两个比特位来标记:00代表出现0次;01代表出现1次,其他的代表出现一次以上。(两个标记位可以表示从1到3)那么位图会变成这样:在这里插入图片描述

此方式虽然可行,但需要第上述代码做出很大变动。那么我们可以采用另一种方式代表两个比特位,即以开两个位图的方式,每个位图的一个比特位组合成两个比特位进行标记:image-20230304183805071

因此,通过这种方式及思想我们甚至可以给任意范围的数字进行标记。那么接下来就实现一下:

template<size_t N>
class twobitset
{
public:void set(size_t x)//标记{if (!_bs1.test(x) && !_bs2.test(x))// 00{//需要变10_bs2.set(x);}else if (!_bs1.test(x) && _bs2.test(x))//10{_bs1.set(x);_bs2.reset(x);//10}//10不变 }void PrintOnce(){for (size_t i = 0; i < N; ++i){if (!_bs1.test(i) && _bs2.test(i)){cout << i << endl;}}cout << endl;}
private:bitset<N> _bs1;//库里的bitset,当然自己写的也可bitset<N> _bs2;
};void test_twobitset()
{twobitset<100> tbs;int a[] = { 3, 5, 6, 7, 8, 9 ,33, 55, 67, 3,3,3,5,9,33 };for (auto e : a){tbs.set(e);}tbs.PrintOnce();
}

image-20230304185259390

这样就完美的解决了这个问题。

二. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

毫无疑问,位图很容易解决在这里插入图片描述

将每个文件种的数都用位图标记,取位图的交集就可以找到文件的交集。

实际上使用位图就是为了去重,如果直接将一个文件的一部分去遍历另一个文件,虽然可以确定,但是难免一个文件中不会出现重复数据,所以使用位图。

三. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

同样的,和第一题的思路相同,并且也是开两个位图进行处理:

  1. 00->0次
  2. 01->1次
  3. 10->两次
  4. 3次及以上

以位图的方式就可以减少空间的占用。

五.经典问题

给一个超过100G大小的log file,log中存放着ip地址,设计算法找到出现次数最多的ip地址。

用map显然是不行的,因为内存过大。位图同样不适用,因为找到出现次数最多的ip地址属于<key, value>的问题,而位图的功能是找在或者不在的问题,以及出现的次数是确定的问题,属于<Key, Key>,所以与位图无关。

100个G显然放不进内存。因此我们要考虑将100G的文件细分成小文件,但是直接细分会导致统计不全,所以采用哈希切分的方式将HashFunc(ip)%100分成100个小的Ai号文件,如果这个小文件超过1G,此时就会出现两种情况:

  1. 这个小文件冲突的ip很多,都是不同的Ip,,大多是不重复的,map统计不下。
  2. 这个小文件冲突的ip很多,都是相同的ip,map可以统计。

直接用map统计,如果是情况2,是可以统计的,不会报错。如果是第一种情况,map会在insert时报错,这是因为New结点失败,失败会抛异常,因此对于第一种情况我们还需要继续通过不同的HashFunc进行切分,直到满足条件为止。

相关文章:

【C++修炼之路】24.哈希应用--位图

每一个不曾起舞的日子都是对生命的辜负 哈希应用--位图哈希应用&#xff1a;位图一.提出问题二.位图概念三.位图代码四.位图应用五.经典问题哈希应用&#xff1a;位图 一.提出问题 问题&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#x…...

4. 字符设备驱动高级--- 下篇

文章目录一、字符设备驱动高级1.1 注册字符设备驱动新接口1.1.1 新接口与旧接口1.1.2 cdev介绍1.1.3 设备号1.1.4 编程实践1.1.5 alloc_chrdev_region自动分配设备号1.1.6 中途出错的倒影式错误处理方法二、字符设备驱动注册代码分析2.1 旧接口register_chrdev2.2 新接口regist…...

ChatGPT介绍以及一些使用案例

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

PCL 点云高斯混合聚类(GMM)

文章目录 一、简介二、算法实现三、实现效果参考资料一、简介 与k均值使用原型向量来刻画聚类结构不同,高斯混合聚类(Mixture-of-Gaussian)采用了概率模型来表达聚类原型。从名字中就可以知晓,该方法将会结合高斯分布来进行聚类过程,该分布的概率密度函数定义如下所示: p (…...

Docker学习(十六)踩坑,如何将对容器的修改同步到基础镜像中

目录1.背景2.解决方法1&#xff09;将容器文件进行归档2&#xff09;创建一个新的 Dockerfile3&#xff09;构建新的基础镜像3.注意事项4.commit命令踩坑记录1.背景 最近接手了一个docker服务&#xff0c;现需要对镜像进行修改&#xff0c;原始的 Dockerfile 已经丢失&#xff…...

食品与疾病关系预测赛题

和鲸平台数据分析实战 题目&#xff1a;食品与疾病关系预测算法赛道 一、赛题描述 食品与疾病关系预测算法赛道 越来越多的证据表明&#xff0c;食物分子与慢性疾病之间存在关联甚至治疗关系。营养成分可能直接或间接地作用于人类基因组&#xff0c;并调节参与疾病风险和疾病…...

Symbol

Symbol是ES6新增的一种基本数据类型 它用来表示独一无二的值&#xff0c; 通过Symbol函数生成 Symbol前面不能加new ,创建symbol类型指的时候传入一个参数&#xff0c;这个参数需要是字符串 使用Symbol函数创建一个symbol类型值&#xff0c;可以给它传入一个字符串参数&#xf…...

NC65 对上年度反结账,调整数据后重新结账后,对本年度年初重算时系统报错:更新记数错误。

1、对上年度反结账,调整数据后重新结账后,对本年度年初重算时系统报错:更新记数错误。 解决方案: 1、在期初余额节点,按Ctrl+ALT+A重建期初凭证; 2、到结账节点,重建余额表,选择有问题的财务核算账簿,注意:会计期间要放空; 3、到期初余额节点,将刚才删除期初数据的…...

位运算相关

文章目录一、求1的个数二、另类加法三、数组中出现一次的数字四、数组中出现一次的数字变形一、求1的个数 二进制中1的个数 法一&#xff1a;逐位判断 根据与&运算 n&10&#xff0c;说明n的最右边一位为0 n&11&#xff0c;说明n的最右边一位为1 所以思路就是&…...

Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号

首先区分一下Linux信号跟进程间通信中的信号量&#xff0c;它们的关系就犹如老婆跟老婆饼一样&#xff0c;没有一毛钱的关系。 信号的概念 信号的概念&#xff1a;信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。比如&#xff1a;红绿灯是一种信号&#xff0c…...

锯齿数组 - 贪心

文章目录锯齿数组 -贪心&#xff08;不过挺像滑动窗口的&#xff09;1144. 递减元素使数组呈锯齿状锯齿数组 -贪心&#xff08;不过挺像滑动窗口的&#xff09; 1144. 递减元素使数组呈锯齿状 题目链接&#xff1a;1144. 递减元素使数组呈锯齿状 题目大意&#xff1a;给你一个…...

[CVPR 2022] Balanced Contrastive Learning for Long-Tailed Visual Recognition

Contents IntroductionMethodPreliminariesBalanced Contrastive Learning (BCL)Drawbacks of SCLClass-averagingClass-complementLower bound of BCLOptimization with Logit CompensationFrameworkExperimentReferencesIntroduction 作者发现对于在长尾数据集上,Supervised…...

23种设计模式-工厂模式

工厂模式是一种创建型设计模式&#xff0c;它提供了一种创建对象的方式&#xff0c;而无需将具体的对象创建逻辑暴露给客户端。在Java中&#xff0c;工厂模式常常用于创建复杂对象或对象的构造过程涉及到多个步骤的情况。 在Android开发中&#xff0c;工厂模式也经常被使用&am…...

Linux操作系统学习(进程等待)

文章目录进程等待进程等待的必要性如何进程等待waiwaitpid验证进程等待 ​ 我们知道fork函数可以创建一个子进程&#xff0c;而子进程通常是替父进程完成一些任务&#xff0c;而父进程在fork之后需要通过wait/waitpid等待子进程退出。这就是进程等待 进程等待的必要性 通过获…...

Docker学习(十八)load 和 import 命令的区别

Docker 中有两个命令可以将本地文件系统中的 tar 文件导入到 Docker 中&#xff1a;docker load 和 docker import。尽管它们的作用类似&#xff0c;但它们之间有一些重要的区别。 1.使用方式的不同&#xff1a; docker load 的使用示例&#xff1a; docker load --input tes…...

mysql中的事务

在日常生活中,我们会遇到一个场景,那就是在转账的时候,A有1000块钱,要给B转账500,那么最后的结果是A有500,B有500,但是也有可能出现A没有钱了,B有1000块,或者在转账过程中卡顿,这是不符合逻辑的,那么这个时候就要使用事务来解决问题 事务就是把一堆sql语句打包成一个整体,要么…...

《C++ Primer Plus》第18章:探讨 C++ 新标准(9)

编程练习 下面是一个简短程序的一部分&#xff1a; int main() {using namespace std;// list of double deduced from list contentsauto q average_list ({15.4, 10.7, 9.0});cout << q << endl;// list of int deduced from list contentscout << averag…...

记录一次PWM信号异常问题

问题我使用单片机输出PWM控制机械臂&#xff0c;但是控制过程中&#xff0c;机械臂总是会出现莫名的抽动。利用示波器测试PWM信号&#xff0c;发现信号正常。过程&#xff08;1&#xff09;在反复的测试过程中&#xff0c;队友提出&#xff0c;将示波器的地线放在左侧的GND波形…...

简单了解---性能测试

目录 一、什么是性能测试 二、常见的性能测试指标 1、并发 2、响应时间 3、事务 4、点击率 5、吞吐量 6、资源利用率 三、性能测试的分类 1、一般测试 2、负载测试 3、压力测试 4、稳定性测试 四、为什么要做性能测试&#xff1f; 五、影响性能的因素有哪些&…...

1.机器学习笔记第一周

机器学习利用领域&#xff1a; 1&#xff1a;随着网络数据增大&#xff0c;需要搜集用户的数据&#xff0c;做喜好性偏向判断等。 2&#xff1a;只要有数据的&#xff0c;无论是医疗领域&#xff0c;还是基因领域都是需要机器学习来发现数据密码。 3&#xff1a;机器自我学习…...

若依学习(前后端分离版)——启动时发生了啥?(@PostConstruct)(mybatis log free)

我们可以发现若依启动时执行了一些sql我们可以安装一个插件mybatis log free 来更好的进行sql查看 &#xff0c;安装后需要修改一下若依的日志配置如下查看日志&#xff0c;我们发现执行了三个方法&#xff08;&#xff09;&#xff0c;分别查询了一些数据。以第二个方法为例子…...

每日十问9c++-内存模型和名称空间

每日十问9c内存模型和名称空间 1.对于下面的情况&#xff0c;应使用哪种存储方案? a.homer 是函数的形参。 b. secret变量由两个文件共享。 c.topsecret 变量由一个文件中的所有函数共享&#xff0c;但对于其他文件来说是隐藏的。 d. beencalled 记录包含它的函数被调用的次数…...

【python】JSON数据类型与Python数据类型之间的转化

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录JSON格式文件JSON格式序列化与反序列化作用JSON常用数据结构键值对的集合值的有序列表JSON数据类型与Python数据类型之间的转化JSON格式和python的区别读写json文件dump 把python 写到json文件load 把json写…...

Spring——什么是事务?传播行为?事务隔离级别有哪些?

思维导图一、什么是事务&#xff1f;多条DML要么同时成功&#xff0c;要么同时失败Transaction&#xff08;tx&#xff09;二、事务的四个过程&#xff1a;开启事务&#xff08;start transaction&#xff09;执行核心业务代码提交事务&#xff08;如果核心业务处理过程中没有出…...

【项目实战】使用Feign服务间相互调用,其实OpenFeign也没有想象中那么难嘛

一、Feign介绍 openfeign是一个java的http客户端,用来简化http调用 二、Feign架构(来自官方) Feign由五大部分组成, 由于刚开始接触 feign ,比较关注的 clients 跟 encoders/decoders 三、OKHTTP与Feign之间的关系 在Feign中,Client是一个非常重要的组件,Feign最终…...

tun驱动之ioctl

struct ifreq ifr; ifr.ifr_flags | IFF_TAP | IFF_NO_PI; ioctl(fd, TUNSETIFF, (void *)&ifr); 上面的代码的意思是设置网卡信息&#xff0c;并将tun驱动设置为TAP模式。在TAP模式下&#xff0c;在用户空间下调用open打开/dev/net/tun驱动文件&#xff0c;发送(调用send函…...

[acwing周赛复盘] 第 93 场周赛20230304

[acwing周赛复盘] 第 93 场周赛20230304 一、本周周赛总结二、 4867. 整除数1. 题目描述2. 思路分析3. 代码实现三、 4868. 数字替换1. 题目描述2. 思路分析3. 代码实现四、4869. 异或值1. 题目描述2. 思路分析3. 代码实现六、参考链接一、本周周赛总结 彩笔了&#xff0c;只A…...

NOIP2022 T4 比赛

P8868 [NOIP2022] 比赛 题目大意 有两个长度为nnn的序列aaa和bbb&#xff0c;有qqq次询问&#xff0c;每次询问给出l,rl,rl,r&#xff0c;求 ∑ilr∑ji1r(max⁡kijak)(max⁡lijbl)\sum\limits_{il}^r\sum\limits_{ji1}^r(\max\limits_{ki}^ja_k)\times(\max\limits_{li}^jb_l…...

计算机组成原理

目录 ❤ 控制器 ❤ 运算器 ❤ 控制器运算器(计算机的中央处理器CPU) ❤ 存储器 内存(主存) 外存 内存和外村的区别 ❤ 输入设备 ❤ 输出设备 ❤ 适配器 ❤ 总线 ❤ 启动计算机的流程 ❤ 机械硬盘 ❤ 固态硬盘 python从小白到总裁完整教程目录:https://b…...

1. 命名规范

1. 命名规范 成绩10开启时间2021年09月17日 星期五 18:00折扣0.8折扣时间2021年11月6日 星期六 00:00允许迟交否关闭时间2021年11月21日 星期日 00:00 家有家法&#xff0c;行有行规。在家有家的规矩&#xff0c;入行有行的规矩。我们计算机一行就有一个命名的规矩&#xff0c;…...