哈希的应用——位图

✅<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而已。而且位图一旦插入之后,他的搜索效率非常高。

相关推荐
小字节,大梦想1 小时前
【C++】二叉搜索树
数据结构·c++
我是哈哈hh2 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
丶Darling.2 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5202 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
Indigo_code3 小时前
【数据结构】【链表代码】合并有序链表
数据结构·windows·链表
jiyisuifeng19913 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
我言秋日胜春朝★3 小时前
【C++】红黑树
数据结构
新晓·故知3 小时前
<基于递归实现线索二叉树的构造及遍历算法探讨>
数据结构·经验分享·笔记·算法·链表
gorgor在码农4 小时前
Mysql 索引底层数据结构和算法
数据结构·数据库·mysql
武昌库里写JAVA5 小时前
【Java】Java面试题笔试
c语言·开发语言·数据结构·算法·二维数组