【 C++ 】bitset位图的模拟实现

news2025/2/26 23:26:30

位图概念

曾经有这样一个面试题,如果给你40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】方法如下:

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

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

在这里插入图片描述

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

bitset大体框架

  • bitset能实现对数字的位的操作,同时也能通过类似于数组的下标来访问各个位的数值,以执行相应的操作。模拟bitset就是用一个普通的数组来存储数据以达到模拟的目的。
  • 如果我们以一个整型作为比特位的容器,那么如果要求0~N范围的比特位,就需要有N/32+1 个整型来容纳这些比特位,同理如果以char为容器,则需要N/8+1个char来容纳N个比特位。这里我们用vector数组作为底层容纳比特位的容器,且其存储的数据类型为char。
#pragma once
#include<iostream>
#include<vector>
using namespace std;
namespace flash
{
	//N个比特位的位图
	template<size_t N>
	class bitset
	{
	public:
		//构造函数
		bitset()
		{
			//+1保证足够比特位,最多浪费8个比特位
			_bits.resize(N / 8 + 1, 0);
		}
		//把x映射的位标记成1
		void set(size_t x)
		{
			//x映射的比特位在第几个char对象
			size_t i = x / 8;
			//x在char第几个比特位
			size_t j = x % 8;
			//利用按位或|把第j位标记成1
			_bits[i] |= (1 << j);
		}
		//把x映射的位标记成0
		void reset(size_t x)
		{
			//x映射的比特位在第几个char对象
			size_t i = x / 8;
			//x在char第几个比特位
			size_t j = x % 8;
			//将1左移 j 位再整体反转后与第 i 个char进行与运算
			_bits[i] &= (~(1 << j));
		}
		//判断指定比特位x的状态是否为1
		bool test(size_t x)
		{
			//x映射的比特位在第几个char对象
			size_t i = x / 8;
			//x在char第几个比特位
			size_t j = x % 8;
			//将1左移 j 位后与第 i 个char类型进行与运算得出结果
			return _bits[i] & (1 << j);
		}
		//翻转指定位x
		void flip(size_t x)
		{
			//x映射的比特位在第几个char对象
			size_t i = x / 8;
			//x在char第几个比特位
			size_t j = x % 8;
			//将1左移 j 位后与第 i 个char进行按位异或运算^即可。
			_bits[i] ^= (1 << j);
		}
		//获取位图中可以容纳位N的个数
		size_t size()
		{
			return N;
		}
		
		//统计set中1的位数
		size_t count()
		{
			size_t count = 0;
			for (auto e : _bits)
			{
				int n = e;
				while (n)
				{
					int m = n - 1;
					n = n & m;
					count++;
				}
			}
			return count;
		}
		//判断所有比特位若无置为1,返回true
		bool none()
		{
			//遍历每个char
			for (auto e : _bits)
			{
				if (e != 0)//说明有位被置为1,返回false
					return false;
			}
			return true;//说明全为0,返回true
		}
		//判断位图中是否有位被置为1,若有则返回true
		bool any()
		{
			return !none();
		}
		//全部NUM个bit位被set返回true
		bool all()
		{
			size_t size = _bits.size();
			//先检查前N-1个char
			for (size_t i = 0; i < size - 1; i++)
			{
				if (~_bits[i] != 0)//取反应该为0,否则取反之前不全为1,返回false
					return false;
			}
			//再检查最后一个char的前 N%8 个位
			for (size_t j = 0; j < N % 8; j++)
			{
				if ((_bits[size - 1] & (1 << j)) == 0)//和test的原理一致
					return false;
			}
			return true;
		}
	private:
		vector<char> _bits;//位图
	};
}

成员函数

构造函数

  • 一个char类型有8个bit位,所以理想状态下N个比特位的位图就需要用到 N/8 个字节,但仅限于N是8的整数倍,如果N位10,那么计算下来就会少2个比特位,因此综合考虑,我们给出 N/8+1 个字节,这样算下来,所需的N个比特位绝对都能访问到,最多可以整除的情况下浪费了8个比特位(1字节)。

而构造函数,我们只需要对这所有的比特位(N/8+1)个字节的大小初始化为0即可。

//构造函数
bitset()
{
	//+1保证足够比特位,最多浪费8个比特位
	_bits.resize( N/8+1, 0);
}

set函数

set的作用是把x映射的位置标记成1,实现规则如下:

  1. 通过x / 8计算x在第i个char类型 。
  2. 通过x % 8计算x在char第j个比特位 。
  3. 利用按位或 | 把第i个char中的第j个比特位置为1。

在这里插入图片描述

//把x映射的位标记成1
void set(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//利用按位或|把第j位标记成1
	_bits[i] |= (1 << j);
}

在这里插入图片描述

reset函数

reset的作用是把把x映射的位标记成0,实现规则如下:

  1. 通过 x/8 计算x在第i个char类型 。
  2. 通过 x%8 计算x在char第j个比特位 。
  3. 将1左移 j 位再整体反转后与第 i 个char类型进行与运算即可。

在这里插入图片描述

//把x映射的位标记成0
void reset(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//将1左移 j 位再整体反转后与第 i 个char进行与运算
	_bits[i] &= (~(1 << j));
}

test函数

test的作用是判断指定比特位x的状态是否为1,实现规则如下:

  1. 通过x / 8计算x在第i个char类型 。
  2. 通过x % 8计算x在char第j个比特位 。
  3. 将1左移 j 位后与第 i个char类型进行与运算得出结果 。
  4. 若结果非0,则该位被设置,否则该位未被设置。

在这里插入图片描述

//判断指定比特位x的状态是否为1
bool test(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//将1左移 j 位后与第 i 个char类型进行与运算得出结果
	return _bits[i] & (1 << j);
}

flip函数

flip的作用是用于翻转指定位,若指定位为0,翻转后为1,若指定位为1,反转后为0,实现规则如下:

  1. 通过x / 8计算x在第i个char类型。
  2. 通过x % 8计算x在char第j个比特位。
  3. 将1左移 j 位后与第 i 个char进行按位异或运算^即可。

在这里插入图片描述

//翻转指定位x
void flip(size_t x)
{
	//x映射的比特位在第几个char对象
	size_t i = x / 8;
	//x在char第几个比特位
	size_t j = x % 8;
	//将1左移 j 位后与第 i 个char进行按位异或运算^即可。
	_bits[i] ^= (1 << j);
}

count函数

count的作用是统计位图中被设计为1的个数,实现规则如下:

  1. n = n & (n-1) => 消去n的二进制数中最右边的1。
  2. n不为零继续执行第一步。
  3. 执行了几次说明n中有多少个1。

在这里插入图片描述

//统计set中1的个数
size_t count()
{
	size_t count = 0;
	for (auto e : _bits)
	{
		int n = e;
		while (n)
		{
			n = n & (n - 1);
			count++;
		}
	}
	return count;
}

size函数

size的作用是获取位图中可以容纳位N的个数。

//获取位图中可以容纳位N的个数
size_t size()
{
	return N;
}

none any all

  1. none:none的作用是遍历每一个char,如果全为0,则none返回true。
//判断所有比特位若无置为1,返回true
bool none()
{
	//遍历每个char
	for (auto e : _bits)
	{
		if (e != 0)//说明有位被置为1,返回false
			return false;
	}
	return true;//说明全为0,返回true
}
  1. any:any的作用判断位图中是否有位被置为1,若有则返回true,这其实和none的作用刚好相反,因此我们直接复用none即可。
//判断位图中是否有位被置为1,若有则返回true
bool any()
{
	return !none();
}
  1. all:all的作用是判断位图中是否所有的位都被置为1,注意这里的特殊性,先前开辟空间时我们为了避免出现N/8不能整除的情况,特地在resize时多开了一个char类型(8比特)的空间,这8比特里面只有前N%8个比特位才是有效的(剩下的都是多开的空间),因此all函数需要分情况讨论:

    • 先检查前n-1个char的二进制是否为全1。
    • 再检查最后一个char的前N%8个比特位是否为全1。
      在这里插入图片描述
//全部NUM个bit位被set返回true
bool all()
{
	size_t size = _bits.size();
	//先检查前N-1个char
	for (size_t i = 0; i < size - 1; i++)
	{
		if (~_bits[i] != 0)//取反应该为0,否则取反之前不全为1,返回false
			return false;
	}
	//再检查最后一个char的前 N%8 个位
	for (size_t j = 0; j < N % 8; j++)
	{
		if ((_bits[size - 1] & (1 << j)) == 0)//和test的原理一致
			return false;
	}
	return true;
}

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

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

相关文章

文献速递:深度学习--深度学习方法用于帕金森病的脑电图诊断

文献速递&#xff1a;深度学习–深度学习方法用于帕金森病的脑电图诊断 01 文献速递介绍 人类大脑在出生时含有最多的神经细胞&#xff0c;也称为神经元。这些神经细胞无法像我们身体的其他细胞那样自我修复。随着年龄的增长&#xff0c;神经元逐渐死亡&#xff0c;因此变得…

袁庭新ES系列12节 | Elasticsearch高级查询操作

前言 上篇文章讲了关于Elasticsearch的基本查询操作。接下来袁老师为大家带来Elasticsearch高级查询部分相关的内容。Elasticsearch是基于JSON提供完整的查询DSL&#xff08;Domain Specific Language&#xff1a;领域特定语言&#xff09;来定义查询。因此&#xff0c;我们有…

Python实现自动检测设备连通性并发送告警到企业微信

背景&#xff1a;门禁机器使用的WiFi连接&#xff0c;因为某些原因会不定期自动断开连接&#xff0c;需要人工及时干预&#xff0c;以免影响门禁数据同步&#xff0c;故写此脚本&#xff0c;定时检测门禁网络联通性。 #首次使用要安装tcping模块 pip install tcpingfrom tcpin…

幻兽帕鲁服务器哪家便宜?阿里云腾讯云京东云华为云对比

幻兽帕鲁服务器哪家便宜&#xff1f;阿里云腾讯云京东云华为云对比&#xff0c;阿里云更便宜&#xff0c;26元1个月。游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;华为云26元&#x…

Android WebView访问网页+自动播放视频+自动全屏+切换横屏

一、引言 近期&#xff0c;我发现电视家、火星直播等在线看电视直播的软件都已倒闭&#xff0c;而我奶奶也再无法通过这些平台看电视了。她已六十多岁&#xff0c;快七十岁啦。这些平台的倒下对我来说其实没有多大的影响&#xff0c;但是对于文化不多的她而言&#xff0c;生活中…

常见需求:CSS 实现弧形卡片的 3 种方式

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ 原文作者&#xff1a;前端侦探 在平时开发中&#xff0c;有时候会碰到下面这种“弧形”样式&#xff0c;主要分为“内凹”和“外凸”两种类型&#xff0c;如下 该如何实现呢&#xff1f;或者想一下&#xff0c;有哪…

用 Pyinstaller 模块将 Python 程序打包成 exe 文件(全网最全面最详细,万字详述)

目录 一、打包前置知识 1.1 什么是 exe 可执行文件&#xff1f; 1.2 为什么要将 Python 程序打包为 exe 可执行文件&#xff1f; 1.3 为什么 Python 程序不能直接运行呢&#xff1f; 1.4 我们用什么来打包 Python 文件呢&#xff1f; 1.5 打包有哪几种分类呢&#xff1f…

Spring-Cloud-Gateway集成Sentinel限流

1&#xff09;gateway添加sentinel相关依赖 <spring-cloud.version>2021.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version><dependencies><!--gateway--><dependency><gro…

多模态表征—CLIP及中文版Chinese-CLIP:理论讲解、代码微调与论文阅读

我之前一直在使用CLIP/Chinese-CLIP&#xff0c;但并未进行过系统的疏导。这次正好可以详细解释一下。相比于CLIP模型&#xff0c;Chinese-CLIP更适合我们的应用和微调&#xff0c;因为原始的CLIP模型只支持英文&#xff0c;对于我们的中文应用来说不够友好。Chinese-CLIP很好地…

为什么要智慧公厕?智慧公厕是做什么的

在现代城市信息化建设进程中&#xff0c;公共卫生设施的建设与管理一直备受关注。而随着科技的迅速发展&#xff0c;智慧公厕作为一种新型的信息化公共设施&#xff0c;正逐渐走进人们的视野。本文以智慧智慧源头厂家广州中期科技有限公司&#xff0c;大量精品案例现场实景&…

【重要公告】BSV区块链协会宣布将启动多项动态安全增强措施

​​发表时间&#xff1a;2024年2月16日 2024年2月16日&#xff0c;瑞士楚格 - BSV区块链协议的管理机构BSV区块链协会&#xff08;以下简称“BSV协会”&#xff09;宣布对其运营模式实施全新的安全架构&#xff0c;其中包括引入网络访问规则和数字资产找回协议&#xff0c;以及…

【非递归版】归并排序算法(2)

目录 MergeSortNonR归并排序 非递归&归并排序VS快速排序 整体思想 图解分析​ 代码实现 时间复杂度 归并排序在硬盘上的应用&#xff08;外排序&#xff09; MergeSortNonR归并排序 前面的快速排序的非递归实现&#xff0c;我们借助栈实现。这里我们能否也借助栈去…

浅谈Unity内存管理

浅谈Unity内存管理 前言 很早之前记录的Unity内存相关的知识点&#xff0c;在此补充到博客上来。有什么不对的地方欢迎指正探讨。 内存概念 虚拟内存&#xff08;Virtual Memory&#xff09; 众所周知&#xff0c;物理内存就是插在计算机主板内存槽上的实际物理内存。 虚拟…

SAP中分包后续调整应用实例二(调减)

之前己写过一篇介绍过分包后续调整功能MB04的基本应用。当时的场景是某个原材料由于各方面原因&#xff08;比如没有维护到BOM中&#xff09;&#xff0c;在委外加工模式成品收货后&#xff0c;并没有消耗或少消耗&#xff0c;这时可以用该事务功能来补充消耗。在生产报工中的M…

redis八股

文章目录 数据类型字符串实现使用场景 List 列表实现使用场景 Hash 哈希实现使用场景 Set 集合实现使用场景 ZSet 有序集合实现使用场景 BitMap实现使用场景 Stream使用场景pubsub为什么不能作为消息队列 数据结构机制SDS 简单动态字符串压缩列表哈希表整数集合跳表quicklistli…

CleanMyMac2024永久免费mac电脑版本安装包下载

CleanMyMac 4 for Mac&#xff1a;细致入微的功能介绍&#xff0c;CleanMyMac 4 for Mac作为一款系统清理和优化工具&#xff0c;提供了丰富而细致的功能&#xff0c;旨在满足Mac用户在不同场景下的清理和优化需求。以下是对CleanMyMac 4功能的更加细化介绍&#xff1a; CleanM…

苍穹外卖 -- day10- Spring Task- 订单状态定时处理- WebSocket- 来单提醒- 客户催单

苍穹外卖-day10 功能实现&#xff1a;订单状态定时处理、来单提醒和客户催单 订单状态定时处理&#xff1a; 来单提醒&#xff1a; 客户催单&#xff1a; 1. Spring Task 1.1 介绍 Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代…

CVE-2021–27065漏洞分析及复现

接着昨天的说 CVE-2021–27065 CVE-2021–27065是⼀个任意⽂件写⼊漏洞&#xff0c;它需要登陆的管理员账号权限才能触发。而CVE-2021–26855正好可以为我们提供了管理员账号权限。 登录管理员账号后,进入:服务器——>虚拟目录——>OAB 编辑OAB配置,在外部链接中写⼊s…

蜣螂优化算法DBO求解不闭合SD-MTSP,可以修改旅行商个数及起点(提供MATLAB代码)

一、蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09; 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁殖行为的启发所得…

【加密算法】AES对称加密算法简介

目录 前言 工作原理 SubBytes ShiftRows MixColumns AddRoundKey 应用场景 在Java中使用AES 加密和解密数据 注意事项和最佳实践 结论 前言 AES&#xff08;Advanced Encryption Standard&#xff09;是一种对称加密算法&#xff0c;它在密码学中被广泛应用。AES取代…