哈希应用位图 | 位图概述与代码实现 | 关于位图的几个面试题

本文介绍了位图的概念,如何通过位图高效地判断大量无序整数是否存在,以及其实现方法,包括添加、删除和查找操作。还探讨了位图在解决特定问题如查找交集和出现次数限制的应用,以及在操作系统中的运用实例。
摘要由CSDN通过智能技术生成

1.位图的概述与实现

当然C++库中也有位图的实现:链接

1.1.位图的引出与概述

面试题:给40亿个不重复的无符号整数(0~2^32),没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中

能不能,将40亿个排序 + 二分查找,又或者整数存放在map或set,理论上是可以的只要你的内存足够大!无符号整数在32位机器下要用32个比特位来存放,我们按40个比特位算40亿个需要160亿个字节,那么1G大概是10亿个字节,存放40亿个无符号整数要16G左右的内存空间,普通配置的电脑是存放不下的!

能不能一个整数对应用一个比特位来标定

32位标定一个整数的状态是在不在,太浪费,我们可以使用1个比特位通过哈希的直接定址法来标定整数的状态。1G是80亿个比特位,那么40亿个无符号整数大概就是0.5G的内存。

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

1.2.位图的代码实现

位图的实现

在这里插入图片描述

一个位图中可以使用vector<int>来存放,40亿有很多个int,我们可以是使用 n / 32找到整数n存放第几个int位置,再通过n % 32找到存放在哪个比特位上,如果是添加,将对应的比特位通过位运算将其置成1即可,如果是删除将对应的比特位通过位运算将其置成0即可。

添加操作

将对应的比特位置成1即可

void set(int n) 
{
	size_t index = n / 32;
	size_t bit_index = n % 32;
	_bitset[index] |= (1 << bit_index);
}

下面假设要将下标为2的比特位置成1:

在这里插入图片描述

让1左移2位,然后或运算,或等是为了改变状态。这里不用考虑大小端的问题,1左移是向高位移动,至于大端还是小端怎么样是机器内部的事!删除和查找是类似的!

删除操作

void reset(int n) 
{
	size_t index = n / 32;
	size_t bit_index = n % 32;
	_bitset[index] &= (~(1 << bit_index));
}

查找操作

bool test(int n) 
{
	size_t index = n / 32;
	size_t bit_index = n % 32;
	return _bitset[index] & (1 << bit_index);
}

完整代码

#include<vector>
#include<iostream>
namespace xiYan
{
	template<size_t N>
	class bitset
	{
	public:

		bitset() {
			_bitset.resize(N, 0);
		}
		void set(int n) 
		{
			size_t index = n / 32;
			size_t bit_index = n % 32;

			_bitset[index] |= (1 << bit_index);
		}
		bool test(int n) 
		{
			size_t index = n / 32;
			size_t bit_index = n % 32;

			return _bitset[index] & (1 << bit_index);
		}
		void reset(int n) 
		{
			size_t index = n / 32;
			size_t bit_index = n % 32;

			_bitset[index] &= (~(1 << bit_index));
		}
	private:
		std::vector<int> _bitset;
	};
}

// 测试代码
#include"bitset.h"
using namespace std;

void main() {
    // 32位大概是43亿个无符号整数,如果是40亿个,我们直接开辟sizt_t的最大值(-1)即可
    // xiYan::bitset<-1> bs;
	xiYan::bitset<100> bs;

	int arr[] = { 1,7,4,3,22,9,7 };

	for (auto num : arr) {
		bs.set(num);
	}
	cout << bs.test(7) << endl;
	cout << bs.test(17) << endl;;


	bs.reset(7);
	cout << bs.test(7) << endl;
    return 0;   
}
1.3.位图的应用及其他面试题
  1. 给定100亿个整数,设计算法找到只出现一次的整数

需要找到出现一次的整数,说明1个比特位标记在不在的状态是不行了!我们可以考虑用两个比特位来标识00 01 10 11其中01标识只出现一次。

在这里插入图片描述

用一个位图中的两个比特位来标识。

在这里插入图片描述

用两个位图对应的比特位来表示,显然是方式2好,可以直接复用位图的结构!方式1要考虑如何切分出两个比特位还需要重新写一遍代码,麻烦些。

方式2的完整代码

#pragma once
#include<vector>
#include<iostream>
#include<bitset>

namespace xiYan
{
	template<size_t N>
	class towBitset
	{
	public:
		void set(int n)
		{
			if (!_one.test(n) && !_tow.test(n)) {
				_one.set(n);
			}
			else if (_one.test(n) && !_tow.test(n)) {
				_tow.set(n);
				_one.set(n);
			}
			else {
				return;
			}
		}
		bool test(int n) {
			return (_one.test(n) && !_tow.test(n));
		}
	private:
		std::bitset<N> _one;
		std::bitset<N> _tow;
	};
}

// 测试代码
#include"bitset.h"
using namespace std;

void test2()
{
	xiYan::towBitset<100> bs;
	// 这里没考虑负数的情况
	int arr[] = { 1,7,7 };

	for (auto num : arr) {
		bs.set(num);
	}
	cout << bs.test(7) << endl;
	cout << bs.test(2) << endl;
	cout << bs.test(1) << endl;
}
  1. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集

在这里插入图片描述

100亿个整数有好多重复的数字,求交集不需要重复的,所以只需要将数据存放到两个位图中,然后对两个位图中的两个对应的位置按位与如果是0则不是交集,非0则是交集。

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

和第一个题相似,只不过,00 01 10 11 则10表示出现两次!

位图的应用

  1. 快速查找某个数据是否在一个集合中
  2. 排序 + 去重
  3. 求两个集合的交集、并集等
  4. 操作系统中磁盘块标记
  5. 操作系统中文件使用open系统调用的flage选项传入多个参数的时候也使用到了位图
int open(const char *pathname, int flags)
int fd = open("log1.txt",O_WRONLY | O_CREAT | O_TRUNC);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值