哈希的应用——位图

✅<1>主页::我的代码爱吃辣

📃<2>知识讲解:数据结构------位图

☂️<3>开发环境:Visual Studio 2022

💬<4>前言:所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的,其本质也是一种hash。但是其占用空间很少。

目录

一.位图概念

二.STL库中的位图

三.模拟实现位图

1.构造函数

2.set

3.reset

4.test

四.完整代码

五.位图的引用


一.位图概念

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

面试体:

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

这40亿个数中。【腾讯】

分析:首先这道题的40亿个无符号整数,如果直接存储到内存的话需要16G的内存,我们首先想到的是使用set,或者unordered_set,但是这里仅仅是数据就已经存储由将近16G大小了,如果我们存放到容器里面,加上一些存储的消耗(指针),实际消耗的内存更是远超16G,这就导致了一般的计算机的内存和普通数据结构来对这些数据进行处理。

所以我们引用一个新的数据结构,就是位图。简单来说仅仅使用一个比特位来标识数据在不在的状态。

  1. 遍历,时间复杂度O(N)
  2. 排序(O(NlogN)),利用二分查找: logN
  3. 位图解决

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

位图也是利用了哈希映射的思想,而且采用的是直接定值映射的方法,最大的区别是位图仅仅使用一个比特位来标识数据是否存在,hash是需要对数据进行存储的。

二.STL库中的位图

STL库中也给我们提供了位图结构bitset,头文件<bitset>

简单介绍几个核心接口:

  • set():将数据插入位图。
  • reset():将数据从位图中挪去。
  • test():判断数据在不在位图中。
cpp 复制代码
int main()
{
	bitset<10000> bit;
	int arr1[] = { 1,15,3,6,8,9,4,23 };
	int arr[] = { 45,12,32,3,6,35,12,78,94,23,62,54 };
	//将arr数据插入位图
	for (auto e : arr)
	{
		bit.set(e);
	}
	//检查arr1,时候出现在位图中
	for (auto e : arr1)
	{
		cout << e << ":" << bit.test(e) << endl;;
	}

	return 0;
}

三.模拟实现位图

C/C++中没有单个比特位类型,最小的也是单个字节的char,所以我们只能使用,char配合vector来存储位图结构。

在定义位图的时候我们可以控制定义的位图存储位数,所以位图的设计我们可以使用一个非类型模板参数来控制。

cpp 复制代码
template<size_t N>
class BitSet
{
public:
	
private:
	vector<char> _map;
};

1.构造函数

假如我们需要开85个比特位,而我们因为最小的开辟单元是char即八比特位,所以如果剩下的不足八比特位,我们仍然按照一个char开辟。

cpp 复制代码
	BitSet()
	{
        //不足一个字节时,就按一个字节开辟,并且全部初始化0
		_map.resize((N / 8) + 1, 0);
	}

2.set

找到需要插入的比特位共需两步:

  1. 找到所在char
  2. 找到所在的比特位
  3. 使用位运算插入
cpp 复制代码
	void set(const int num)
	{
		size_t i = num / 8;
		size_t j = num % 8;
		_map[i] |= 1 << j;
	}

3.reset

reset与set在查找位置时,步骤一致仅仅是在最后一步换成使用位运算将最后一位变为0.

cpp 复制代码
	void reset(const int num)
	{
		size_t i = num / 8;
		size_t j = num % 8;
		_map[i] &= ~(1 << j);
	}

4.test

先找到需要判断的位置,在使用位运算判断。

cpp 复制代码
	bool test(const int num)
	{
		size_t i = num / 8;
		size_t j = num % 8;
		return _map[i] & (1 << j) ;
	}

四.完整代码

cpp 复制代码
template<size_t N>
class BitSet
{
public:
	BitSet()
	{
		_map.resize((N / 8) + 1, 0);
	}

	void set(const int num)
	{
		size_t i = num / 8;
		size_t j = num % 8;
		_map[i] |= 1 << j;
	}

	void reset(const int num)
	{
		size_t i = num / 8;
		size_t j = num % 8;
		_map[i] &= ~(1 << j);
	}

	bool test(const int num)
	{
		size_t i = num / 8;
		size_t j = num % 8;
		return _map[i] & (1 << j) ;
	}

private:
	vector<char> _map;
};

测试:

五.位图的引用

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

回顾刚才的面试题:

我们将40亿的整数全部存入位图,仅仅才占有512M而已。而且位图一旦插入之后,他的搜索效率非常高。

相关推荐
Hera_Yc.H9 小时前
数据结构之一:复杂度
数据结构
肥猪猪爸10 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos10 小时前
环形缓冲区
数据结构
readmancynn11 小时前
二分基本实现
数据结构·算法
Bucai_不才11 小时前
【数据结构】树——链式存储二叉树的基础
数据结构·二叉树
盼海11 小时前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步11 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
珹洺12 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
几窗花鸢12 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
.Cnn12 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论