哈希重要思想——位图详解

一,概念

所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。
为了方便理解我们引入一道面试题,

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

两个思路:
1.排序+二分
2.set+find
首先40亿个整数占用多少内存?
1G约等于10亿字节,40亿个整数有160亿字节,也就是大约16G左右,
16G是绝对会内存超限的,所以正常的方法我们都不可以使用。

这就要用到位图的思想,我们用比特位去存储数据,一个比特位就是一个数据
因为是存无符号整数,所以最大的数就是2^32,那我们就开这么大的范围。
2^32比特位是多大呢?
是512MB,变小了非常多。
例如50,就如下存储。
在这里插入图片描述

找位置

如何找到相应的位置?
还是以50为例。
1.先找到50在第几个整型中
50/32==1

2.50在这个整型的第几个比特位中
50%32==18

总结:
如何找到x对应的位置

  1. x在第i个整型中 i=x/32
  2. x在这个整型的第j个比特位中 j=x%32

二,模拟实现位图

在这里插入图片描述
这是库中给我们提供的位图,他有比较核心的三个函数组成分别是:set,reset,test。

1.set

set就是把x映射的位标记位1。
在这里插入图片描述
这里用到的位操作是:|

代码

//把x映射的位标记为1void set(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] |= (1 << j);}

2.reset

和set的作用相反reset是把x映射的位置标记位0
在这里插入图片描述

代码

		//把x映射的位标记为0void reset(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);}	

3.test

test查看指定位置是否为1
在这里插入图片描述

代码

		//查看是否有值bool test(size_t x){size_t i = x / 32;size_t j = x % 32;return _bits[i]&(1 << j);//0为假,非0就是真}

全代码

	template<size_t N>class bitset{public:bitset(){_bits.resize(N / 32 + 1, 0);//cout << N << endl;}//把x映射的位标记为1void set(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] |= (1 << j);}//把x映射的位标记为0void reset(size_t x){size_t i = x / 32;size_t j = x % 32;_bits[i] &= ~(1 << j);}	//查看是否有值bool test(size_t x){size_t i = x / 32;size_t j = x % 32;return _bits[i]&(1 << j);//0为假,非0就是真}private:vector<int> _bits;};

测试

	void test_bitset(){bitset<100> bs1;bs1.set(50);bs1.set(30);bs1.set(90);for (size_t i = 0; i < 100; i++){if (bs1.test(i)){cout << i << "->" << "在" << endl;}else{cout << i << "->" << "不在" << endl;}}}

三,面试题(位图拓展)

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

还是先算100亿个整数占多少内存,
1G是10亿字节,100亿个整数大概40G内存
刚刚是统计在不在,而这里是统计次数,那我们的思路就是用两个位图来统计
00:表示出现0次
01:表示出现1次
10:表示2次及以上

实现

1.set

如果是00就把他变成01
如果是01就把他变成10

		// 00 -> 01// 01 -> 10void set(size_t x){// 00 -> 01if (_bs1.test(x) == false && _bs2.test(x) == false){_bs2.set(x);}// 01 -> 10else if (_bs1.test(x) == false && _bs2.test(x) == true){_bs1.set(x);_bs2.reset(x);}}
2.test

这就是单纯的返回值就好了

		int test(size_t x){// 00 -> 01if (_bs1.test(x) == false && _bs2.test(x) == false){return 0;}// 01 -> 10else if (_bs1.test(x) == false && _bs2.test(x) == true){return 1;}else{return 2;}}

测试

	void test_bitset2(){int a[] = { 5,7,9,2,5,99,5,5,7,5,3,9,2,55,1,5,6 };two_bit_set<100> bs;for (auto e : a){bs.set(e);}for (size_t i = 0; i < 100; i++){//cout << i << "->" << bs.test(i) << endl;if (bs.test(i)){cout << i << endl;}}}

完整代码

	template<size_t N>class two_bit_set{public:// 00 -> 01// 01 -> 10void set(size_t x){// 00 -> 01if (_bs1.test(x) == false && _bs2.test(x) == false){_bs2.set(x);}// 01 -> 10else if (_bs1.test(x) == false && _bs2.test(x) == true){_bs1.set(x);_bs2.reset(x);}}int test(size_t x){// 00 -> 01if (_bs1.test(x) == false && _bs2.test(x) == false){return 0;}// 01 -> 10else if (_bs1.test(x) == false && _bs2.test(x) == true){return 1;}else{return 2;}}private:bitset<N> _bs1;bitset<N> _bs2;};

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

两个位图做相与操作

3. 一个文件有100亿个整数,1G内存,设计算法找到出现次数不超过2次的所有整数。

这个就是第一个的变形,我们增加一个11记录三次及以上的数,把1次和2次的整数找出来即可。

4.给定100亿个整数,设计算法找到只出现一次的整数(限制512MB内存)

这题难在限制了内存,100亿整数按照常规位图操作要1G的空间才行。
还是开两个位图,分两次统计,第一次只统计<2^31大小的值
第二次统计剩余的值即可。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/695795.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电商数据接口|如何获取电商数据?

随着互联网的发展&#xff0c;电商的运营方式也逐渐数据化&#xff0c;在大数据的影响下&#xff0c;电商领域很大程度上改变了传统的运营模式。很多商家如今都非常重视数据&#xff0c;并将数据贯穿于整个店铺的运营之中。 那么&#xff0c;具体来说电商大数据有哪些妙用呢&a…

作业帮重启k12,保底年薪150万。。。

作业帮 近期&#xff0c;一位学而思前员工在脉脉上爆料发问&#xff1a; 收到猎头电话&#xff0c;说作业帮重启 K12&#xff0c;K12 主讲无责保底年薪 150W&#xff0c;base 北京。 楼下评论区一位新东方在职员工表示&#xff0c;似乎有这事儿&#xff1a; 而另外一个网友则表…

集合系列(二十五) -二叉树、平衡二叉树、红黑树性能总结

一、摘要 二叉树&#xff0c;作为一种数据结构&#xff0c;在实际开发中&#xff0c;有着非常广泛的应用&#xff0c;尤其是以平衡二叉树、红黑树为代表&#xff0c;在前几篇文章中&#xff0c;我们详细的介绍了BST、AVL、RBT的算法以及代码实践&#xff0c;下面简要概括描述一…

object.key()用法

object.key(obj) 一、概念&#xff1a;返回一个由一个给定对象的自身可枚举属性组成的数组。 二、用法&#xff1a; 1、参数为对象&#xff1a;则返回为 对象属性名组成的数组。 let obj {日期&#xff1a;date,姓名&#xff1a;userName,地址:address}console.log(Object.k…

栈结构(详解)

1.栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&am…

计算机网络复习-应用层

概述 传输层以及以下的层提供完整的通信服务&#xff0c;不需要管传输&#xff0c;只需要往上对接用户即可。应用层是面向用户的一层 定义应用间通信的规则 应用进程的报文类型 (请求报文、应答报文)报文的语法、格式应用进程发送数据的时机、规则 DNS详解 DNS&#xff1a…

分布式与一致性协议之PBFT算法(二)

PBFT算法 如何替换作恶的主节点 虽然PBFT算法可以防止备份节点作恶&#xff0c;因为这个算法是由主节点和备份节点组成的&#xff0c;但是&#xff0c;如果主节点作恶(比如主机点接收到了客户端的请求&#xff0c;但就是默不作声&#xff0c;不执行三阶段协议)&#xff0c;那…

STM32使用ESP01S连接阿里云物联网平台

一、ESP01S烧录MQTT固件准备 首先准备好烧录工具&#xff0c;可以从官网上进行下载。 MQTT固件官网网址&#xff1a;AT固件汇总 | 安信可科技 (ai-thinker.com) 进去后如下图界面&#xff0c;向下翻找找到MQTT固件&#xff08;1471&#xff09;下载固件即可。 烧录工具光网地…

沃比得 DP16A 对数周期天线 100MHz~6GHz

沃比得DP16A对数周期天线该天线可用做超短波发射或接收天线&#xff0c;工作频率为 100MHz&#xff5e;6GHz。具 有频带宽&#xff0c;性能可靠&#xff0c;增益高等优点&#xff0c;是理想的无线电频谱管理、EMC 测试、电子对抗等领域 的定向接收、发射天线。 应用领域 ●…

【spring】application.yml导入额外配置文件

有时候application.yml 已经配置很多配置已经很大很乱了想把他们拆出去放在一个独立的XX.yml文件管理。这时候就用到了 spring.config.import 属性。 spring.config.import spring.config.import 是 Spring Boot 2.4 版本引入的一个配置属性&#xff0c;用于导入额外的配置数…

IT小能手秘籍:看工单与任务单如何携手玩转服务管理

在ITSM这摊事儿里&#xff0c;我们有两种手段来管理IT小哥们忙活的那些维护工作&#xff0c;一种叫工单&#xff08;Ticket&#xff09;&#xff0c;另一种则是任务单&#xff08;Task&#xff09;。这哥俩到底有啥不同&#xff0c;又怎么互相帮衬着呢&#xff1f; 工单嘛&…

react18【系列实用教程】moxb —— 集中状态管理 (2024最新版)

官方文档 https://www.mobxjs.com/ moxb 和 redux 都能用于 react 的状态管理&#xff0c;但 moxb 更简单&#xff0c;适合规模不大的应用 &#xff08;规模大的应用若合理组织代码结构&#xff0c;也能用 moxb&#xff09; 安装 moxb npm i mobx npm i mobx-react-lite此处安…