Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C++】位图

【C++】位图

作者头像
青衫哥
发布于 2023-04-24 03:39:08
发布于 2023-04-24 03:39:08
39100
代码可运行
举报
文章被收录于专栏:C++打怪之路C++打怪之路
运行总次数:0
代码可运行

前言

我们先来看腾讯曾经的一道面试题: 给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在 这40亿个数中。 常规方法: 1. 遍历,时间复杂度 O(N) 2. 排序 (O(NlogN)) ,利用二分查找 : logN 这道题如果是不可能用常规方法来解决的,因为存储40亿个整形需要的空间太大了,高达16G。 这种情况,我们就可以用到今天的主角—— 位图 给定的每个整形只有两种状态:在与不在,我们完全可以通过一个比特位的0和1来记录每个数字在不在。这样大大节省了空间,只需要500MB的空间即可。


一、概念

所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用

来判断某个数据存不存在的。


二、代码实现

底层结构我们用一个vector,容器中存储的类型为char。因为一个char类型占用一个字节,我们将八个比特位(一个字节)分为一个区间。

1.set

功能:将给定的数字对应的比特位数字标记为1。

关于数字的位置:我们怎么确定一个数字在第几个字节的第几个比特位呢? 其实很简单,因为一个字节是八个比特位的大小,所以 数字的字节位置 = 数字 / 8,数字的比特位位置 = 数字 % 8。 我们知道,0和1或上一个1,那么该位都为1。所以我们只需要把对应的位置或上1即可。

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void set(size_t x)
{
	//i表示在第几个字节,j表示在第几个比特位
	size_t i = x / 8;
	size_t j = x % 8;

	_bits[i] |= (1 << j);
}

2.reset

功能:将给定的数字对应的比特位数字标记为0。

如何做到保证其他位数字不变,特定位置的数字置零呢? 0和1与1都等于它本身,而0和1与0都等于0,所以我们只需要其他位与1,而对应的位置与0,即可做到置零。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void reset(size_t x)
{
	size_t i = x / 8;
	size_t j = x % 8;

	//与上的数字其他位都是1,为了让其他位保持不变
	//需要reset的位置与上0,为了让其置零
	_bits[i] &= (~(1 << j));
}

3.test

功能:判定给定的数字对应的比特位数字是否为1。

只需要该位与1,如果该位为0,与1后的数字为0。该位为1,与1后的数字不为零。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bool test(size_t x)
{
	size_t i = x / 8;

	size_t j = x % 8;

	return _bits[i] & (1 << j);
}

完整代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once
#include <vector>
namespace BitSet
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			//_bits.resize(N / 8 + 1, 0);
			_bits.resize((N >> 3) + 1, 0);
		}

		void set(size_t x)
		{
			//i表示在第几个字节,j表示在第几个比特位
			size_t i = x / 8;
			size_t j = x % 8;

			_bits[i] |= (1 << j);
		}

		void reset(size_t x)
		{
			size_t i = x / 8;
			size_t j = x % 8;

			//与上的数字其他位都是1,为了让其他位保持不变
			//需要reset的位置与上0,为了让其置零
			_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;
	};

}

三、位图的应用

1. 快速查找某个数据是否在一个集合中 2. 排序 + 去重 3. 求两个集合的交集、并集等 4. 操作系统中磁盘块标记

面试题:

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

一个数字有三种状态:0次、1次、超过一次。所以我们需要用两个比特位来记录。由于用连续的两个比特位来记录会比较麻烦,我们可以开两个位图,各用一位来记录高位和地位。

这样就能复用我们的bitset了。 

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			if (!_bs1.test(x) && !_bs2.test(x)) //00
			{
				_bs2.set(x);
			}
			else if (!_bs1.test(x) && _bs2.test(x))	//01
			{
				_bs1.set(x);
				_bs2.reset(x);
			}
			//10不需要管

		}
		void PrintOnce()
		{
			for (size_t i = 0; i < N; ++i)
			{
				if (!_bs1.test(i) && _bs2.test(i))
				{
					cout << i << endl;
				}
			}
		}


	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

}

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

思路也很简单,我们开两个位图,如果两个位图中的某一位同时为1,那么就是两个文件的交集。 注意:虽然是100亿个整数,但是整形最大范围还是42亿多,所以是不需要开100亿个空间的。

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

其实和第一题的解法一样,只不过现在需要多加一种状态,那就是超过2次的我们标记为:11。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C++语法中bitset位图介绍及模拟实现
给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。
芯动大师
2023/10/14
2770
C++语法中bitset位图介绍及模拟实现
【C++】位图
给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中❓
平凡的人1
2023/10/15
1980
【C++】位图
C++ 哈希的应用【位图】
位图(bitset)是一种特殊的数据结构,仅仅依靠 0、1 表示当前位置是否有数据存在,常用于对查找速度和存储空间有着高要求的场景中,除此之外,位图还可以配合宏定义,实现同时传递多个参数,比如系统调用 open,其中的参数2(打开方式)就是一个简单的位图结构
北 海
2023/07/28
3330
C++ 哈希的应用【位图】
C++位图
其次是set和哈希表。set自动可以排序且在红黑树中查找速度也很快。但要把40亿个整数加上红黑树的节点(三叉链外加颜色)放进内存里,内存明显不够,不可取;哈希表同样是把40亿个整数外加节点放进内存里,内存明显不够,也不可取。
梨_萍
2023/04/24
4940
C++位图
【C++】哈希应用:位图 哈希切分 布隆过滤器
1. 大厂经典的面试题,给你40亿个不重复的无符号整数,让你快速判断一个数是否在这40亿个数中,最直接的思路就是遍历这40亿个整数,逐一进行比对,当然这种方式可以倒是可以,但是效率未免太低了。 另一种方式就是排序+二分的查找,因为二分查找的效率还是比较高的,logN的时间复杂度,但是磁盘上面无法进行排序,排序要支持下标的随机访问,这40亿个整数又无法加载到内存里面,你怎么进行排序呢?所以这样的方式也是不可行的。 那能不能用红黑树或者哈希表呢?红黑树查找的效率是logN,哈希表可以直接映射,查找的效率接近常数次,虽然他们查找的效率确实很快,但是40亿个整数,那就是160亿字节,10亿字节是1GB,16GB字节红黑树和哈希表怎么能存的下呢?这还没有算红黑树的三叉链结构,每个结点有三个指针,而且哈希表每个结点会有一个next指针,算上这些的话需要的内存会更大,所以用红黑树或哈希表也是无法解决问题的。
举杯邀明月
2023/04/12
6360
【C++】哈希应用:位图 哈希切分 布隆过滤器
【C++修炼之路】24.哈希应用--位图
数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。
每天都要进步呀
2023/03/28
2750
【C++修炼之路】24.哈希应用--位图
【C++高阶】哈希—— 位图 | 布隆过滤器 | 哈希切分
之前我们已经在这篇文章中 【C++高阶】哈希函数底层原理全面探索和深度解析-CSDN博客
IsLand1314
2024/10/15
1690
【C++高阶】哈希—— 位图 | 布隆过滤器 | 哈希切分
【C++】位图应用 | 布隆过滤器
给40亿个不重复的无符号整数,没排过序,给一个无符号整数,如何快速判断一个数是否在这40亿个数中
lovevivi
2023/10/17
2100
【C++】位图应用 | 布隆过滤器
【C++】哈希(位图,布隆过滤器)
给 40亿个不重复的无符号整数, 没排过序。给一个无符号整数,如何快速判断一个数是否在
The sky
2023/04/12
3240
【C++】哈希(位图,布隆过滤器)
【C++从小白到大牛】位图讲解
给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】
用户11316056
2024/10/16
1110
【C++从小白到大牛】位图讲解
C++:哈希拓展-位图
第二种方法就是先排序+二分查找:肯呢个有些人会觉得,排序的代价太大了;其实不然,我们只需要排序一次那么接下来的查找就好办了; 对于二分查找,效率是O(logn),根据2^10=1024,那2^30的数量级就是10^9,就已经上升到亿了,2^32大约就是40亿;所以我们使用二分在40亿个数中查找一个数最多只需要查找32次就可以了,效率是相当客观的;
啊QQQQQ
2024/11/19
620
C++:哈希拓展-位图
位图/布隆过滤器/海量数据处理方式
所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的。
二肥是只大懒蓝猫
2023/03/30
4000
位图/布隆过滤器/海量数据处理方式
哈希应用
所谓位图,就是用每一个比特位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的
芝士就是菜
2023/04/20
4390
哈希应用
【C++进阶】位图/布隆过滤器与海量数据处理
我们知道数据的最小存储位是比特(bite),每个比特位只能是0或1,我们用1和0来表示在或不在,或是其它类型的状态信息,这种结构称作位图。
aosei
2024/01/23
1650
【C++进阶】位图/布隆过滤器与海量数据处理
C++哈希应用-位图/布隆过滤器/海量数据处理
C++位图/布隆过滤器/海量数据处理 零、前言 一、位图 1、位图概念 2、位图接口的介绍以及实现 3、位图的应用 二、布隆过滤器 1、布隆过滤器概念和介绍 2、布隆过滤器的操作及实现 3、布隆过滤器的分析 三、海量数据处理 零、前言 本章主要讲解C++中对哈希的应用有关方面的内容,位图,布隆,海量数据处理 一、位图 1、位图概念 位图概念: 位图其实就是哈希的变形,同样通过映射来处理数据,只不过位图本身并不存储数据,而是存储标记 通过一个比特位来标记这个数据是否存在,1代表存在,0代表不
用户9645905
2022/11/30
5440
C++哈希应用-位图/布隆过滤器/海量数据处理
哈希的应用——位图
所以上面这些思路都不太合适,而且我们这里只是要判断在不在,其实没必要把它们全部存起来。
YIN_尹
2024/01/23
2040
哈希的应用——位图
【数据结构】哈希经典应用:位图——[深度解析](8)
YY的秘密代码小屋
2024/01/23
3310
【数据结构】哈希经典应用:位图——[深度解析](8)
位图与布隆过滤器
此篇文章针对大量数据进行筛选或者判断重复,存在等一系列侧重于在特定空间,时间等允许范围内进行选择的问题提出解决方案。
羑悻的小杀马特.
2025/01/23
1030
位图与布隆过滤器
【C++】STL --- 哈希
在 C++98 中,STL 提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 O(logN),即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在 C++11 中,STL 又提供了4个 unordered 系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同,本文中只对 unordered_map 和 unordered_set 进行介绍,unordered_multimap 和 unordered_multiset 大家可以查看文档介绍 - - - unordered_multimap / unordered_multiset.
YoungMLet
2024/03/01
1930
【C++】STL --- 哈希
C++:位图和布隆过滤器
问题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在 这40亿个数中。【腾讯】
小陈在拼命
2024/05/10
1290
C++:位图和布隆过滤器
相关推荐
C++语法中bitset位图介绍及模拟实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验