哈希的应用——位图

✨前言✨

📘 博客主页:to Keep博客主页
🙆欢迎关注,👍点赞,📝留言评论
⏳首发时间:2024年5月17日
📨 博主码云地址:博主码云地址
📕参考书籍:《C++ Primer》《C++编程规范》
📢编程练习:牛客网+力扣网
**由于博主目前也是处于一个学习的状态,如有讲的不对的地方,请一定联系我予以改正!!!

1 位图的应用

我们先来了解一下腾讯的经典面试题

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

想到快速查找,首先我们想到的就是哈希表,但是哈希表对于如此海量的数据,有那么大内存放的下吗?我们可以粗略的估计一下我们所需要的内存大小!首先,一个int是4个字节,40亿个数字就是160亿字节,1G大约是10亿字节,也就是说,40亿个数字就要16G!显然这些数据放到内存中就很大了!于是位图就有了应用场景了!
可以明确的一点就是,对于数据就两种情况,那就是在和不在两种场景,也就是0和1就可以表示了,那么我们不就可以使用比特位来表示一个数字是否存在了!也就是说40亿个数字,只需要用40亿个比特位来判断就行了,也就相当于5亿多个字节就搞定,也就是说花费0.5G就能搞定了!

2 位图的实现

2.1 位图的实现原理

位图的实现原理其实很简单,就是利用vector去帮我们开辟一段连续整形的内存空间,结合左移与右移的相关操作,对比特位进行操作。比特位为1表示当前数字存在,0表示不存在

2.2 左移与右移

在位图中,我们主要是对比特位进行操作,所以我们这里需要简单回顾一下左移与右移操作!左移就是由低位向高位移动,右移就是由高位向低位移动!万万不可以简单理解为向左边移动,向右边移动!如下图所示就是一个例子,右边才是高位:
在这里插入图片描述

假设我们要想表示数字56放到对应的比特位上,我们就要确定56在那个位置!所以我们先利用i = 56/32表示56在vetcor的第几个位置,j =56%32就可以确定在当前区间的那个位置了,也就是对应的在那个比特位上!然后我们再利用vector[i] |= (1<<j)就可以把56这个数据放到对应的位置上了!

2.3 位图重要函数的实现

构造函数,需要注意的是位图开多大空间,取决于数据的大小,这里是int类型,所以是除以32

	MyBitSet()
	{
	//有N个数字,转化成开多少个整形字节的顺序表
		v1.resize(N/32+1,0);
	}

set函数

void set(size_t x)
{
	size_t i = x / 32;
	size_t j = x % 32;
	//不改变其他比特位,只把当前要处理的数字放进对应的比特位
	v1[i] |= (1 << j);
}

reset函数

void reset(size_t x)
{
	size_t i = x / 32;
	size_t j = x % 32;
	//不改变其他比特位,把当前处理的数字的比特位置为0
	v1[i] &= ~(1 << j);
}

test函数

bool test(size_t x)
{
	size_t i = x / 32;
	size_t j = x % 32;
	//判断当前数字对应的比特为是0还是1
	return v[i] & (1 << j);
}

3 位图的总结

也就是说位图对于这种海量数据(只能解决整型的)具有明显的优势所在,本质也是和哈希一样,通过建立对应的映射关系,从而实现快速的查找与修改!还有一些经典的面试题,如下所示:

  1. 给定100亿个整数,设计算法找到只出现一次的整数?
  2. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?
  3. 1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

对于上述面试题的实现代码思路:位图的实现
其实也是利用位图进行解决,这里是1G内存,结合上面所说的,可以开辟两个整形的位图,但是如果要求512M,只能开一个位图又该如何进行处理呢?当然必须利用我们的切分思想,例如将数据分为0-2^31为一段,第二段开始用后面的数字开始减去2的31次方,又映射到位图中,完成相对映射来判断就可以了!

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

to Keep

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

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

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

打赏作者

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

抵扣说明:

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

余额充值