当前位置: 首页 > 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;机器自我学习…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Vue 模板语句的数据来源

&#x1f9e9; Vue 模板语句的数据来源&#xff1a;全方位解析 Vue 模板&#xff08;<template> 部分&#xff09;中的表达式、指令绑定&#xff08;如 v-bind, v-on&#xff09;和插值&#xff08;{{ }}&#xff09;都在一个特定的作用域内求值。这个作用域由当前 组件…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

C++--string的模拟实现

一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现&#xff0c;其目的是加强对string的底层了解&#xff0c;以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量&#xff0c;…...