【数据结构】哈希经典应用:位图——[深度解析](8)

前言

大家好吖,欢迎来到 YY 滴 数据结构 系列 ,热烈欢迎! 本章主要内容面向接触过C++的老铁
主要内容含:
在这里插入图片描述

欢迎订阅 YY滴C++专栏!更多干货持续更新!以下是传送门!

一.位图的基本概念

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

二.位图的原理

  • 哈希—— 直接定址法
  • 例:
    在这里插入图片描述
  • 在实际场景中,我们的机器一般是 小端机(从左到右,从大到小排布)
  • 所以真正的场景一般如下:
    在这里插入图片描述
  • 小端机性质 证明:
    在这里插入图片描述

三.位图(bitset)的代码实现(逐过程解读)

【1】位图的文档查看

  • 我们可以重点关注红圈圈出的三个位图常用函数
    在这里插入图片描述

【2】把X映射的那个标记成1——对应biteset中的set

在这里插入图片描述

【3】把X映射的那个标记成0——对应biteset中的reset

在这里插入图片描述

【4】判断某位是1还是0——对应biteset中的test

在这里插入图片描述

【5】位图的完整实现

#include<vector>

namespace bit
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_a.resize(N / 32 + 1);//位图的初始化,确定分为多少块
		}

		// x映射的那个标记成1
		void set(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;

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

		// x映射的那个标记成0
		void reset(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;

			_a[i] &= (~(1 << j));
		}

		bool test(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;

			return _a[i] & (1 << j);
		}
	private:
		vector<int> _a;
	};
}

四.位图的经典应用场景

【※】对数据大小&转换的基本概念

  • 1G =1024 MB=10241024 BK=10241024*1024 Byte= 2^30 byte = 10亿+ byte
  • 例:我们判断40亿个整数需要多少G呢?
    分析:40亿个int,160亿byte,根据10亿byte对应1G,160亿byte对应16G

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

  • 分析:常规思路是遍历/排序+二分查找
  • 遍历的时间复杂度是O(N),排序(O(NlogN))+二分查找 logN
  • 显然对于40亿无符号整数来说,需要占用16G,占用资源过于庞大,不妥
  • 快速判断在不在,显然是位图经典场景,利用位图解决:
  • 数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:
    在这里插入图片描述

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

  • 分析:我们可以用两个位图来控制,我们可以这样设计
    在这里插入图片描述
  • 代码展示设计思路如图所示:
template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			// 00 -> 01
			if (!_bs1.test(x) && !_bs2.test(x))
			{
				_bs2.set(x);
			} // 01 -> 10
			else if (!_bs1.test(x) && _bs2.test(x))
			{
				_bs1.set(x);
				_bs2.reset(x);
			}
			// 本身10代表出现2次及以上,就不变了
		}

		bool is_once(size_t x)
		{
			return !_bs1.test(x) && _bs2.test(x);
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

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

  • 此题的设计思路与上面的【2】基本一致,设计上要稍作改动:
    在这里插入图片描述
  • 代码展示设计思路如图所示:
template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
			// 00 -> 01
			if (!_bs1.test(x) && !_bs2.test(x))
			{
				_bs2.set(x);                        //出现一次
			} // 01 -> 10
			else if (!_bs1.test(x) && _bs2.test(x))
			{
				_bs1.set(x);
				_bs2.reset(x);                    //出现两次
			}// 10 -> 11
			else if (_bs1.test(x) && !_bs2.test(x))
			{
				_bs2.set(x);                      //出现三次
			}
			// 此外代表出现3次及以上,就不变了
		}

		bool max_two(size_t x)
		{
			return (_bs1.test(x) && !_bs2.test(x))||(!_bs1.test(x) && _bs2.test(x));   //10 或者 01
		}
	private:
		bitset<N> _bs1;
		bitset<N> _bs2;
	};

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

  • 分析:
  • 第一种思路是:把其中一个文件存入位图,遍历另一个文件元素,将问题转变成"在不在"问题
  • 问题缺陷: 这种问题存在去重问题,即多次重复(下图中,交集明明只有一个3,但是会出现多个重复的3交集)
    在这里插入图片描述
  • 分析:
  • 第二种思路是:将两个文件映射到两个位图中去(实现去重)
  • 如果相对应的位置都是1(满足相&为1),则此元素就在交集中
  • 44
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YY的秘密代码小屋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值