高阶数据结构 位图的模拟实现

news2024/9/23 9:30:28

作者:@学习同学
专栏:@数据结构进阶
作者简介:大二学生 希望能和大家一起进步!
本篇博客简介:模拟实现高阶数据结构位图

位图的模拟实现

  • bitset类要实现的接口函数总览
  • bitset类的模拟实现
    • 位图结构
    • 构造函数
    • set reset flip test
    • size count
    • any none all
    • 打印函数
  • 位图代码

本文所有的代码都是在32位的环境下编译运行
并且所有成员函数都用于设置指定位

bitset类要实现的接口函数总览

在这里插入图片描述

bitset类的模拟实现

位图结构

我们在使用位图的各种性质的时候 需要这种结构支持随机访问

所以我们会选择vector对象来当他的成员变量

模板代码如下

	template<size_t N> //模板的偏特化 具体知识可以在我的博客 模板进阶中学习
	class bitset
	{
	public:
	private:
		vector<int> _bits;
	};

构造函数

在构造位图的时候我们要根据给定的整数N构造一个N个位大小的位图

按照一个int类型四个字节的大小判断 我们vector每个数据占大小32个位

所以说 假设我们需要32位的位图 就需要开一个整型的空间

假设我们需要64位的位图 就需要开两个整型的空间

除以32就可以了

那么这里问题就出现了 假如我们要开一个24位的空间呢

很显然我们无法指定开出3/4个字节的大小 那么这个时候的处理方式是什么呢

我们说这里的解决方式就是开空间的时候 额外开一个整型的空间大小

这样子操作只有一个缺点 就是最多会浪费一个整型的空间 但是对于我们的计算机来说一个整型的空间也不算什么

在这里插入图片描述

代码表示如下

		// 构造函数 
		bitset()
		{
			_bits.resize(N / 32 + 1, 0); // 多开一个字节空间防止不能被整除
		}

set reset flip test

set用于设置位

比如我们想设置第34个位 我们可以通过除以32来找到它在vector的第几个数据中

之后我们可以通过模32找到它在这个数据的第几个位中

设置位图中的指定位的步骤如下

  1. 通过上面的方式计算出要设置的位在第i个整数的第j个位置
  2. 将1左移j个位置之后和第i和整数进行或运算

代码和示例图表示如下

在这里插入图片描述

		void set(size_t pos)
		{
			// 1. 计算出pos第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行或操作
			_bittest[i] |= 1 << j; // 将该位设置为1
		}

我们来测试下写的代码

在这里插入图片描述
我们可以发现 容器中的第一个数变成了四

而实际上这就是将第二位设置为1的结果

reset的成员函数用于清空位

找位置还是和设置位一样的算法

接下来步骤如下

  1. 按照前面的算法 找到第i个整数的第j位
  2. 将1左移j位之后反转并且与第i个整数按位与

代码和示例图表示如下

在这里插入图片描述
我们来测试下写的代码

在这里插入图片描述
我们可以发现 整数变成了0

flip成员函数用于反转位

找位置还是和设置位一样的算法

接下来的步骤如下

  1. 按照前面的算法 找到第i个整数的第j位
  2. 将1左移j位之后并且与第i个整数按位与

代码和示例图表示如下

在这里插入图片描述
我们可以发现 异或之后除了指定位置之外 其他所有的位置都没有变化

		void flip(size_t pos)
		{
			// 1. 计算出pos的第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行异或操作
			_bits[i] ^= (1 << j);
		}

我们来测试下写的代码
在这里插入图片描述
我们可以发现容器中的第一个数变成了四

而实际上就是第二位被反转了

test的成员函数用于获取位的状态

找位置还是和设置位一样的算法

接下来步骤如下

  1. 按照前面的算法 找到第i个整数的第j位
  2. 将1左移j位之后与第i个整数按位与
  3. 如果与出来的结果是非0 则该位未被设置 反之则被设置

这里是两种按位与的结果
在这里插入图片描述

代码和示例图表示如下

		bool test(size_t pos)
		{
			// 1. 计算出pos的第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行与操作
			int test = _bits[i] & (1 << j);

			// 3. 判断是否指定位为0
			if (test == 0)
			{
				return false;
			}
			else // 非0
			{
				return true;
			}
		}

我们来测试下代码

在这里插入图片描述
我们可以发现被设置之后test结果为真

而被重新设置之后test的结果为假

size count

size成员函数用于获取容器可以容纳位的个数

这个很简单 我们直接返回非类型模板参数就可以了

代码和演示图如下

		size_t size()
		{
			return N;
		}

在这里插入图片描述

count成员函数用来获取容器中被设置的位的个数

简单来说这个函数其实就是获取容器中1的个数

对于这个算法目前来说最高效的就是这样子 假设原本的数字是n

我们使用n 与上 (n - 1)

  1. 如果是0 则说明1的个数是1
  2. 如果是非0 则n等于上面的结果继续重复操作

接下来步骤如下

  1. 按照上面的算法找出1的个数
  2. 返回1的个数
		size_t count()
		{
			// 使用count计数来作为最终值
			size_t count = 0;
			// 1. 遍历整个vector数组 使用算法找出1的个数
			for (auto e : _bits)
			{
				int x = e;
				while (x)
				{
					x = x & (x - 1);
					count++;
				}

				// 2. 返回最终的结果
				return  count;
			}
		}

我们来测试下代码

在这里插入图片描述
我们可以发现设置了四个位 最后计数的结果也是四

any none all

any成员函数用于获取图中是否有被设置

只要有位被设置容器中的数就会变成非0

因此我们只需要遍历整个容器看看是否有数是非0就可以

代码和演示结果如下

		bool any()
		{
			// 遍历每个整数
			for (auto x : _bits)
			{
				if (x != 0) // 该整数不是0
				{
					return true;
				}
			}
			return false;
		}

在这里插入图片描述

none成员函数用来判断位图中是否全部位都未被设置

这个很简单我们直接复用any就行

代码和演示结果如下

		bool none()
		{
			// 复用any
			return !(this->any());
		}

在这里插入图片描述

all成员函数用来判断是否所有的位都被设置成1

这个应该是实现的所有成员函数中最难的一个了

因为我们不光要考虑容器的所有位 还需要考虑被浪费的空间

大概思路如下

  1. 检查前面N-1个数的二进制是否都是1
  2. 检查第N个数的前N%32个bit位是否都是1

代码和运行结果如下

		bool all()
		{
			// 1. 首先查看前面N-1个数是否为全1
			int x = N / 32;
			while (x)
			{
				if (~(_bits[x]))
				{
					return false;
				}
				x--;
			}

			// 2. 看看第N个数是否前面y位是否为1
			x = N / 32;
			int y = N % 32;
			while (y)
			{
				if ((_bits[x] & (1 << y)) == 0)
				{
					return false;
				}
				y--;
			}
			return true;
			
		}

打印函数

我们可以将位图中所有的位打印出来

整体的思路还是和上面的all差不多 为了防止位图越界的问题

我们先遍历位图的前面N-1个数

之后在遍历位图的第N个数的前面N%32个位

		void Print()
		{
			// 1. 先遍历前面N-1个数 
			int x = N / 32;
			while (x)
			{
				int j = 0;
				for  (int i  = 0;  i < 32;  i ++)
				{
					if (_bits[j] & (1 << i))
					{
						cout << "1" << " ";
					}
					else
					{
						cout << "0" << " ";
					}
				}
				j++;
				x--;
			}

			// 2. 遍历后面的数
			x = N / 32;
			int y = N % 32;
			while (y)
			{
				if (_bits[x] & (1<<y))
				{
					cout << "1" << " ";
				}
				else
				{
					cout << "0" << " ";
				}
				y--;
			}
		}

在这里插入图片描述

位图代码

namespace shy // 防止命名冲突 
{
	template<size_t N> //模板的偏特化 具体知识可以在我的博客 模板进阶中学习
	class bitset
	{
	public:
		// 构造函数 
		bitset()
		{
			_bits.resize(N / 32 + 1, 0); // 多开一个字节空间防止不能被整除
		}


		void set(size_t pos)
		{
			// 1. 计算出pos第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行或操作
			_bits[i] |= 1 << j; // 将该位设置为1
		}


		void reset(size_t pos)
		{
			// 1. 计算出pos的第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行与操作
			_bits[i] &= (~(1 << j));
		}

		void flip(size_t pos)
		{
			// 1. 计算出pos的第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行异或操作
			_bits[i] ^= (1 << j);
		}


		bool test(size_t pos)
		{
			// 1. 计算出pos的第i个整数的第j位
			int i = pos / 32;
			int j = pos % 32;

			// 2. 进行与操作
			int test = _bits[i] & (1 << j);

			// 3. 判断是否指定位为0
			if (test == 0)
			{
				return false;
			}
			else // 非0
			{
				return true;
			}
		}

		size_t size()
		{
			return N;
		}

		size_t count()
		{
			// 使用count计数来作为最终值
			size_t count = 0;
			// 1. 遍历整个vector数组 使用算法找出1的个数
			for (auto e : _bits)
			{
				int x = e;
				while (x)
				{
					x = x & (x - 1);
					count++;
				}

				// 2. 返回最终的结果
				return  count;
			}
		}


		bool any()
		{
			// 遍历每个整数
			for (auto x : _bits)
			{
				if (x != 0) // 该整数不是0
				{
					return true;
				}
			}
			return false;
		}

		bool none()
		{
			// 复用any
			return !(this->any());
		}

		bool all()
		{
			// 1. 首先查看前面N-1个数是否为全1
			int x = N / 32;
			while (x)
			{
				if (~(_bits[x]))
				{
					return false;
				}
				x--;
			}

			// 2. 看看第N个数是否前面y位是否为1
			x = N / 32;
			int y = N % 32;
			while (y)
			{
				if ((_bits[x] & (1 << y)) == 0)
				{
					return false;
				}
				y--;
			}
			return true;

		}

		void Print()
		{
			// 1. 先遍历前面N-1个数 
			int x = N / 32;
			while (x)
			{
				int j = 0;
				for  (int i  = 0;  i < 32;  i ++)
				{
					if (_bits[j] & (1 << i))
					{
						cout << "1" << " ";
					}
					else
					{
						cout << "0" << " ";
					}
				}
				j++;
				x--;
			}

			// 2. 遍历后面的数
			x = N / 32;
			int y = N % 32;
			while (y)
			{
				if (_bits[x] & (1<<y))
				{
					cout << "1" << " ";
				}
				else
				{
					cout << "0" << " ";
				}
				y--;
			}
		}
		private:
			vector<int> _bits;
	};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/181719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全国地级市1999—2020年用地面积指标(建设用地\居住用地\绿地\建成区等)

在之前的文章中我们介绍过基于2000-2021年《中国城市统计年鉴》整理的人口相关指标&#xff0c;包括人口及户数数据和人口变动数据&#xff08;可查看之前推送的文章&#xff09;。 本次我们对2000—2021年的《中国城市统计年鉴》中的用地面积相关的指标进行了整理&#xff0c…

lego-loam学习笔记(二)

前言&#xff1a; 对于lego-loam中地面点提取部分的源码进行学习。 地面点提取在src/imageProjection.cpp中的函数groundRemoval()。内容比较少&#xff0c;容易理解。 size_t lowerInd, upperInd;float diffX, diffY, diffZ, angle; lowerInd表示低线数的点云&#xff1b; …

从网络摄像头拉流的几种方法(python代码)

文章目录摘要&#x1f407;1、直接使用OpenCV&#x1f407;2、使用ffmpeg&#x1f407;2.1、安装方法 &#x1f407;2.1.1、安装ffmpeg-python &#x1f407;2.1.2、安装FFmpeg &#x1f407;2.2、代码实现&#x1f407;3、多线程的方式读取图片&#x1f407;4、多进程的方式拉…

DocuWare 智能文档控制——杜绝成堆的文件和文件混乱,保证业务连续性,创建企业新阶段

一、智能文档控制——杜绝成堆的文件和文件混乱&#xff0c;保证业务连续性&#xff0c;创建企业新阶段 清晰有条理和即时可用的信息是成功的业务流程的关键&#xff0c;随时随地安全管理业务文档&#xff0c;快速查找并智能使用它们。 1、安全存储 使用安全的集中式平台存放…

44.Isaac教程--姿态估计

二维骨骼姿态估计 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录二维骨骼姿态估计应用概述推理运行推理在嵌入式平台上运行推理消息类型小码推理示例训练步骤 1. 先决条件 安装 Docker 容器步骤 2. 安装步骤 3. 下载 COCO 2017 和预处理…

高效学 C++|函数参数的引用传递和函数重载

在节前拜读张哥dvlinker的博客_CSDN博客-VC常用功能代码封装,C相关,C软件调试与异常排查从入门到精通系列教程领域博主的C专栏后&#xff0c;毅然决然&#xff0c;想在春节期间系统的学习下C入门知识&#xff0c;本文算是学习过程的小结及感悟&#xff01; C语言中函数的声明形…

pytorch深度学习一机多显卡训练设置,流程

最近在学习在服务器的ubuntu环境上配置用多个显卡训练&#xff0c;之前只用一个显卡训练实在是太慢了点 先看看服务器上有几个显卡&#xff1a; nvidia-smi即可得到具体的显卡信息&#xff1a; 每个显卡之前有对应的编号。 然后得知自己服务器上总共有多少显卡后&#xff0…

第一章:Go语言简介

Go语言&#xff08;或 Golang&#xff09;起源于 2007 年&#xff0c;并在 2009 年正式对外发布。Go 是非常年轻的一门语言&#xff0c;它的主要目标是“兼具 Python 等动态语言的开发速度和 C/C 等编译型语言的性能与安全性”。 Go语言是编程语言设计的又一次尝试&#xff0c…

41-剑指 Offer 43. 1~n 整数中 1 出现的次数

题目 输入一个整数 n &#xff0c;求1&#xff5e;n这n个整数的十进制表示中1出现的次数。 例如&#xff0c;输入12&#xff0c;1&#xff5e;12这些整数中包含1 的数字有1、10、11和12&#xff0c;1一共出现了5次。 示例 1&#xff1a; 输入&#xff1a;n 12 输出&#x…

【Activiti工作流引擎】基本认识Activiti

Activiti工作流引擎 表的命名结构 ACT_RE &#xff1a;RE’表示 repository。这个前缀的表包含了流程定义和流程静态资源 &#xff08;图片&#xff0c;规则&#xff0c;等等&#xff09;。 ACT_RU&#xff1a;RU’表示 runtime。这些运行时的表&#xff0c;包含流程实例&am…

海外拥有最庞大社区人群的Verasity($VRA),后市值得期待

在2023年开年以来&#xff0c;随着主流标的回暖进一步带动大盘的上涨&#xff0c;并且加密货币总市值重回1亿美元以上。而加密货币市场大多数资产都迎来普涨。我们看到&#xff0c;短时的上涨虽然为市场重新注入信心&#xff0c;但能够持续具备上涨趋势的标的并不多。此前&…

layui框架实战案例(18):保存草稿和单选radio复选框checkbox无focus属性快速聚焦跳转的解决方案

系列文章目录 layui动态表格翻页和搜索的代码分析layui框架实战案例(3)&#xff1a;layui上传错误请求上传接口出现异常解决方案layui框架实战案例(9)&#xff1a;layPage 静态数据分页组件layui框架实战案例(10)&#xff1a;短信验证码60秒倒计时layui框架实战案例(11)&#…

SSE(Server-sent Events)实现Web消息推送(SpringBoot)

本文参考自&#xff1a; Web消息推送之SSE_魅Lemon的博客-CSDN博客_sse推送 【IT老齐237】超好用Web服务端主动推送技术SSE_哔哩哔哩_bilibili 1、Web消息推送简介 短轮询 长轮询 iframe流 SSE MQTT websocket 2、SSE原理介绍 2.1、概念 SSE(Server Sent Event)&…

43.Isaac教程--图像变形

图像变形 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录图像变形几何畸变图像投影透视畸变校正径向畸变校正切向畸变校正其他相机固有参数焦距主点&#xff08;投影中心&#xff09;未失真输出的光学特性输出主点输出焦距输出图像大小输…

最快的树视图组件:Flexible TreeView.NET Crack

为什么要使用灵活的 TreeView&#xff1f; 灵活性 市场上其他类似树视图的组件所不具备的无与伦比的可扩展性和独特功能。 表现 市场上最快的树视图组件。 仅需 0.39 秒即可添加 100,000 个节点。 简单 尽管是一个非常强大的树视图组件&#xff0c;但 Flexible TreeView 被设计…

Java开发基于rmi的数据库中间件设计源码,并利用中间件建立一个数据库应用(Java web项目),分布式对象技术课程实践

基于rmi的数据库中间件设计 介绍 分布式对象技术课程实践&#xff1a;基于rmi的数据库中间件设计&#xff0c;并利用中间件建立一个数据库应用&#xff08;Java web项目&#xff09;。 软件架构 前端&#xff1a;React后端&#xff1a;Springboot数据库中间件&#xff1a;J…

【人脸检测】------MTCNN算法

MTCNN算法出自深圳先进技术研究院,乔宇老师组,是今年2016的ECCV。 正如上图所示,该MTCNN由3个网络结构组成(P-Net,R-Net,O-Net)。 Proposal Network (P-Net):该网络结构主要获得了人脸区域的候选窗口和边界框的回归向量。并用该边界框做回归,对候选窗口进行校准,然后通…

Ubuntu18.04下QT和MYSQL异常问题排查处理常用命令

问题场景 &#xff1a;开年第一天上班&#xff0c;使用GIT下载好项目代码到本地后&#xff0c;发现QT5.14.2无法正常启动&#xff0c;使用命令sudo /opt/Qt5.14.2/Tools/QtCreator/bin/qtcreator后没有任何反应&#xff0c;仔细回想应该是年前电脑修改环境变量导致无法进入系统…

微信小程序安全系列——文本内容安全识别

前言 相信很多朋友跟我遇到过相同的问题&#xff0c;就是在开发一些笔记或者博客的时候&#xff0c;会遇到一些过滤敏感、时政、黄、赌、毒这类词汇、句子等这种棘手问题。 今天我们看一下微信小程序提供的文本安全内容识别&#xff0c;也可以减少一些我们的工作量。通过微信…

【通信原理(含matlab程序)】实验二:FM的调制和解调

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; 本人持续分享更多关于电子通信专业内容以及嵌入式和单片机的知识&#xff0c;如果大家喜欢&#xff0c;别忘点个赞加个关注哦&#xff0c;让我们一起共同进步~ &#x…