当前位置: 首页 > article >正文

C++笔记---位图

1. 位图的概念

位图(Bitmap)是一种基于位操作的数据结构,用于表示一组元素的集合信息。它通常是一个仅包含0和1的数组,每个元素对应一个二进制位,若该元素存在,则对应的位为1;若不存在,则为0。位图的这种表示方式使得它能够在存储上以极高的空间效率来管理大规模数据。位图特别适用于需要频繁查询和更新的场景,如数据库索引、图像处理和网络协议等。

简单来说,就是一个采用直接定址法的哈希表,只不过一个bit位映射一个数。

底层通常是一个存储整形的数组或vector,将其中的整形数据连起来看作一个存储bit位的数组。下标为n的bit位为1代表n存在,为0代表n不存在。

这样一来,位图存储一个数据的消耗仅为一个bit位,相比于红黑树和哈希表,在对大量的整形数据的进行增删查改时,位图的优势就十分明显了。

优点:增删查改效率极高,空间复杂度低。

缺点:只适用于整型。

2. 位图的实现

STL的 "bitset" 就是位图,其有三个主要接口:set(插入),reset(删除),test(查找)。

bitset - C++ Reference

位图的实现比较简单,就不过多介绍了。

namespace lbz
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
			:_bs(N / 32 + 1, 0)
		{}

		void set(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;

			_bs[i] |= (1 << j);
		}

		void reset(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;
			
			_bs[i] &= ~(1 << j);
		}

		bool test(size_t x)
		{
			size_t i = x / 32;
			size_t j = x % 32;

			return _bs[i] & (1 << j);
		}
	private:
		vector<int> _bs;
	};

 注意,这里无需在意大小端的问题,因为bit 位的下标只是假想的下标。

我们只需要算出代表x的bit位是哪一个整形中的第几个,并保证各个接口采用相同的逻辑查找即可。

3. 位图的应用

3.1 检查数据是否存在

eg:给40亿个不重复的无符号整数,没排过序。如何判断某个无符号数是否在这40亿个数中?(腾讯、百度等公司出过的面试题)。

思路1:暴力遍历--->时间复杂度O(N),太慢

思路2:排序+二分查找--->时间复杂度O(N * logN) + O(logN),排序消耗大,但是排好序之后可以进行多次查找。

但是上面两种思路都存在着一个问题,那就是需要将40亿个整数存到内存中。

40亿个整数约等于16GB,考虑到电脑中的其他进程,开出这么大的一个数组显然是不现实的。

这时候就可以使用位图来解决,位图中开辟 "UINT_MAX" 个字节(数据范围为0~UINT_MAX),并将数据存储到位图中。此时,数据对内存的占用就可以降低到500MB左右,且查找效率为O(1)

3.2 计算数据个数

eg:给100亿个不重复的无符号整数,没排过序。如何找出出现次数小于2的数据?

一个bit位只能判断存不存在,如果要计数,就只能用多个比特位来映射一个数。

这里,我们可以采用包装多个位图的方式来实现,第一个位图存储第一个bit位,第二个位图存储第二个bit位,以此类推。

template<size_t N>
class two_bitset
{
public:
	void set(size_t x)
	{
		bool bit1 = _bs1.test(x);
		bool bit2 = _bs2.test(x);

		if (!bit1 && !bit2)// 00 + 1
		{
			_bs2.set(x);
		}
		else if (!bit1 && bit2)// 01 + 1
		{
			_bs1.set(x);
			_bs2.reset(x);
		}
		else if (bit1 && !bit2)// 10 + 1
		{
			_bs2.set(x);
		}
	}

	void reset(size_t x)
	{
		_bs1.reset(x);
		_bs2.reset(x);
	}

	int test(size_t x)
	{
		bool bit1 = _bs1.test(x);
		bool bit2 = _bs2.test(x);

		if (!bit1 && !bit2)// 00
		{
			return 0;
		}
		else if (!bit1 && bit2)// 01
		{
			return 1;
		}
		else if (bit1 && !bit2)// 10
		{
			return 2;
		}
		else
		{
			return 3;
		}
	}
private:
	bitset<N> _bs1;
	bitset<N> _bs2;
};

先简单介绍一下,之后可能更新。


http://www.kler.cn/news/367568.html

相关文章:

  • 别名联想路径,前端项目输入@/自动出提示目录和文件
  • Java面试题——微服务篇
  • fetch: 取消请求、读取流、获取下载进度...
  • Leetcode刷题笔记12
  • 《 C++ 修炼全景指南:十七 》彻底攻克图论!轻松解锁最短路径、生成树与高效图算法
  • 认识和使用 Vite 环境变量配置,优化定制化开发体验
  • PHP如何抛出和接收错误
  • C语言[求x的y次方]
  • 7.hyperf安装【Docker】
  • 京东电商下单黄金链路:防止订单重复提交与支付的深度解析
  • Pseudo Multi-Camera Editing 数据集:通过常规视频生成的伪标记多摄像机推荐数据集,显著提升模型在未知领域的准确性。
  • 背包九讲——混合背包问题
  • 虾类图像分割系统:改进亮点优化
  • 前端项目接入sqlite轻量级数据库sql.js指南
  • ffmpeg视频滤镜: 色温- colortemperature
  • Windows 11 绕过 TPM 方法总结,24H2 通用免 TPM 镜像下载 (Updated Oct 2024)
  • java项目之在线考试系统设计与实现(springboot)
  • 通过AWS Bedrock探索 Claude 的虚拟桌面魔力:让 AI 代替你动手完成任务!
  • 时间数据可视化基础实验(南丁格尔玫瑰图)——Python热狗大胃王比赛数据集
  • 蓝桥杯普及题
  • Android中导入讯飞大模型ai智能系统
  • nodejs写入日志文件
  • Linux: Shell编程中的应用之基于sh进行数据统计
  • 【C++ 真题】B2106 矩阵转置
  • 基于java SpringBoot和Vue校园求职招聘系统设计
  • 【牛客算法】某司面试算法题:设计LRU缓存结构