【C++】bitset位图的简单模拟实现及常见面试题

🌏博客主页: 主页
🔖系列专栏: C++
❤️感谢大家点赞👍收藏⭐评论✍️
😍期待与大家一起进步!



前言

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

数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。比如:
在这里插入图片描述

一、 bitset模拟实现

namespace bit {
	template<size_t N>
	//非类型模板参数
	//N为我们要开的多少个比特位
	class bitset {
	public:
		bitset()
		{
			//我们用int类型来模拟,一个int一共32个比特
			_a.resize(N / 32 + 1);
		}

		void set(size_t x) {
			//将对应比特位变为1
			int i = x / 32;
			//i为在第几个int中
			int j = x % 32;
			//j为在这个int的32个比特位的哪个位置
			_a[i] |= (1 << j);
			//按位或::只有双方对应位置都是0的时候才为0

		}

		void reset(size_t x) {
			//将对应比特位变为0
			int i = x / 32;
			int j = x % 32;
			_a[i] &= (~(1 << j));
			//按位与::只有双方对应位置都是1的时候才为1
			//左移后按位取反,相当于除了j位置为0其他位置都为1,按位与的时候其他位
			//不受影响
		}

		bool test(size_t x) {
		//判断这个位置存不存在
			int i = x / 32;
			int j = x % 32;
			//这里按位与并没有改变原来值的大小,
			//因为返回的是一个临时变量
			return _a[i] & (1 << j);
		}

	private:
		vector<int> _a;
	};

在这里插入图片描述
在这里插入图片描述

二、 常见面试题

1.给你一百亿个整数,找到只出现一次的数字

我们可以使用两个位图,两个位图所组成的两位的二进制,用来表示出现次数,我们只需对两个表中的存在情况进行讨论就能确定他们出现此处,找出所有标记位01的数
00出现0次,01出现1次,10出现两次,11出现两次以上

template<size_t N>
	class twobitset
	{
	public:
		void set(size_t x)
		{
		//00出现0次,01出现1次,10出现两次,11出现两次以上
			// 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;
	};

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

两个文件分别放到位图里面,然后判断两个位图的相同位置值是否相同。

int main()
{
	int a1[] = {1,2,3,3,4,4,4,4,4,2,3,6,3,1,5,5,8,9 };
	int a2[] = {8,4,8,4,1,1,1,1};

	bit::bitset<10> bs1;
	bit::bitset<10> bs2;

	// 去重
	for (auto e : a1)
	{
		bs1.set(e);
	}

	// 去重
	for (auto e : a2)
	{
		bs2.set(e);
	}

 	int N=10;
 	//N为两个文件中的最大值
	for (int i = 0; i < N; i++)
	{
	//遍历如果在两个位图中相同位置都为1说明为交集
		if (bs1.test(i) && bs2.test(i))
		{
			cout << i << " ";
		}
	}
	cout << endl;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值