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

【C++】STL详解(十四)—— bitset(位图)的模拟实现 今天我们比较详细地完成了bitset(位图)的模拟实现,了解了一些有关的底层原理。接下来,我们将进行布隆过滤器的学习。希望我的文章和讲解能对大家的学习提供一些帮助。 阅读详情

位图概念

曾经有这样一个面试题,如果给你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;
}
告别乱码!手把手教你用docx4j实现Word转PDF(附完整中文字体配置) 本文详细介绍了如何使用纯Java库docx4j实现Word到PDF的精准转换,并重点解决了中文乱码这一核心痛点。文章提供了从环境搭建、核心代码实现到中文字体配置的完整教程,特别针对Linux服务器部署场景,给出了详细的字体安装与映射方案,确保跨平台转换的稳定性和准确性。 阅读详情

相关推荐

退火朗之万动力学采样

退火朗之万动力学采样(Simulated Annealing Langevin Dynamics Sampling)结合了退火技术和朗之万动力学,是一种用于分子模拟和统计物理中的计算方法。这种方法可以帮助系统从局部最小值中逃逸,以找到全局最小值或进行有效的配置空间探索。

weixin_39699362的博客 1949

C++——bitset

bitset——简单又方便的位运算工具

JAN6055的博客 1万+

Python大数据舆情分析系统开发实战

舆情监测系统是大数据分析的重要应用场景,通过自然语言处理(NLP)技术解析社交媒体文本情感倾向。基于Python技术栈的解决方案整合了Scrapy爬虫框架进行数据采集,PySpark处理海量文本数据,结合SnowNLP和Jieba实现中文语义分析。系统采用微服务架构设计,包含数据采集层、处理层、存储层和应用层,通过情感分析优化和实时热点检测算法提升监测准确率。典型应用包括企业品牌监测、公共事件预警等场景,开发过程中需特别注意数据合规性和分布式集群的性能调优。

weixin_34408624的博客 387

C++基础之bitset

类模板std::bitset template <size_t N> class bitset; 头文件 #include <bitset> 说明 一个bitset中保存了一些bit(字节, 只能取两个值的元素:0或1,真或假 …) bitset模拟了一个bool类型的数组,但是优化了内存空间:总的来说,每个元素值占用一个bit(比大多数系统中最小的元素char小了8倍) 每个位置的都可以独立的访问:例如,给定一个bitset命名为foo,foo[3]访问的就是第四个元素,就像通常数

itlilyer的博客 4499

双足步行机器人的ZMP与CoP检测

静态步行与动态步行   机器人步态分为静态步行和动态步行。当机器人做静态步行运动时,身体的各个部分运动速度很小,机器人的整体稳定性较易控制。静态步行稳定性采用机器人的重心地面投影点(Center of Gravity,简称CoG)作为稳定性标准,这种判定方法适用于运动较为缓慢的情况。如果机器人采用的是一种高速运动的步行方式,则称之为动态步行。当机器人进行动态步行时,其重心的位置和加速度的大小时...

weixin_34112208的博客 5908

卫朋:IPD流程落地之产品开发验证阶段解读

IPD验证阶段

产品线负责人 1486

bitset(C++实现)

位图实际上就是一个指定比特位个数的连续内存空间,所以可以用STL内置的容器vector管理,除此之外,理论上任何类型都可以作为元素的类型,只不过为了容易理解,它的每个元素的类型被设定为char。

Man9o 2190

RK3568平台开发系列讲解(安卓篇)LED呼吸灯系统流程

1.app层封装后使用NotificationManager发出:NotificationManager.notify() 2.Android 系统架构中:一个manager类对应一个aidl接口,一个manager对应一个底层的服务,notification也是这个架构

内核笔记 3646

C++STL详解(十一)-- 位图(bitset)

有一道面试题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中?内存内查找: 面对40亿个无符号整数,我们可以使用搜索树和哈希表,时间复杂度也就为O(1),因为搜索树不仅存储数据,还要存储颜色,parent,child指针等,哈希表还要存储迭代器,size等内置成员,进而导致内存存不下.文件内查找:排序 + 二分查找,时间复杂度为0(1),但是数据太大,只能放在文件上,但是磁盘运行效率太低,不好支持二分查找).综合以上情况,我们可以采取位图解决。

清欢Allen的技术博客 2519

SPMI协议学习总结

SPMI(System Power Management Interface)是由MIPI(Mobile Industry Processor Interface)联盟定义的一种硬件接口标准,它主要用于移动设备中,连接SoC(System on Chip)处理器系统的集成电源控制器与一个或多个电源管理IC(PMIC),以实现精确的电源管理

歌颂苦难的行为是无耻的; 1082

国债期货的日线趋势跟踪策略实现(基于backtrader框架)

通过backtrader框架,我们可以轻松地实现国债期货的日线趋势跟踪策略,并进行回测和验证。通过这种策略,我们可以尝试捕捉国债期货价格的短期趋势,并根据趋势的方向进行交易决策。backtrader提供了许多内置的指标、订单类型和其他功能,可以帮助你进一步优化和改进你的策略。它提供了丰富的工具和功能,使我们能够快速实现和验证我们的交易想法。方法中,我们根据当前价格和前一天的价格判断趋势的方向,并根据趋势的变化进行买入或卖出操作。然后,我们设置了初始资金和交易手续费,并将我们定义的策略。来跟踪每日的收盘价。

NisyPhilosophy的博客 404

c++bitset详解

通常我们是使用的数据类型都是以字节为单位的,bitset中的一个元素一般只占1 bit,相当于一个char元素所占空间的八分之一,int的三十二分之一,特定的情况可以节约大量内存空间,另外完美支持了各种运算操作。下面,就让我们来仔细研究有关bitset的相关知识吧!

浪子回头 1508

在Centos上从零开始部署并运行TinyWebServer服务器,过程记录(非常详细)

TinyWebServer是个什么项目?它是Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器。使用线程池+非阻塞socket+epoll(ET和LT均实现) +事件处理(Reactor和模拟Proactor均实现) 的并发模型使用状态机解析HTTP请求报文,支持解析GET和POST请求访问服务器数据库实现web端用户注册、登录功能,可以请求服务器图片和视频文件实现同步/异步日志系统,记录服务器运行状态。......

AnChenliang_1002的博客 3021

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

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中? 要判断一个数是否在某一堆数中,我们可能会想到如下方法: - 将这一堆数进行排序,然后通过二分查找的方法判断该数是否在这一堆数中。 - 将这一堆数插入到unordered_set容器中,然后调用find函数判断该数是否在这一堆数中。

m0_72532428的博客 1334

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Cpp::STL—位图bitset的使用与模拟实现(39)

Hello,我们又倒回来更新C++篇了好焦虑,时常在想着该如何调节~~好像不算太难,接下来我们要学的布隆过滤器才算是一个重点!

tan180°的博客 1420

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++ bitset(位图)的模拟实现

判断方式比较简单,每一个整数的所有比特位,只要有一个为1,那该整数就肯定不等于0,所以,我们可以遍历所有整数,只要有一个整数不等于0,那就说明有1,返回true,否则所有整数都是0,没一个1,返回false。需要注意的是,如果位图没有包含最后一个整数的全部比特位,那么最后一个整数的二进制无论如何都不会为全1,所以在判断最后一个整数时应该只判断位图所包含的比特位。例如,假如我们要建立一个50个比特位的位图,就需要两个int大小,共64个比特位,使用前50个比特位,后14个舍弃不用就好。的大小是否符合预期。

m0_74189279的博客 1129

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C++进阶(七)--STL--bitset(位图)的介绍与基本功能模拟实现

实际在这个问题当中,我们只需要判断一个数在或是不在,即只有两种状态,那么我们可以用一个比特位来表示数据是否存在,如果比特位为1则表示存在,比特位为0则表示不存在。无符号整数总共有232个,因此记录这些数字就需要232个比特位,也就是512M的内存空间,内存消耗大大减少。方式一: 构造一个16位的位图,所有位都初始化为0。方式二: 构造一个16位的位图,根据所给值初始化位图的前n位。方式三: 构造一个16位的位图,根据字符串中的0/1序列初始化位图的前n位。位图的优缺点:优点:增删查改快,节省空间。

weixin_65132948的博客 990

【C++进阶】bitset位图介绍以及模拟实现

先来看下边一道面试题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。对这些数进行排序,再通过二分算法,查找这个数是否存在插入到unordered_set中,使用find函数查找是否存在数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。

weixin_61654591的博客 692

C++语法中bitset位图介绍及模拟实现

对于上图来说,有一个整形数组,我们可以使用直接定址法对数组的数据进行映射,但是与之前不同的是,此时只是使用一个比特位来代表一个整形数据,当这个数存在时,比特位置1,不存在时,比特位置0,此时就可以大大节省空间资源,无符号整数只有2的32次方个,所以最多开2的32次方个空间,一个空间为一个比特,所以最终只需要512MB的空间。由于不能按位开空间,所以我们选择每次开一个字节的空间,由于有范围最大为N,一位关联一个数据,所以需要开N/8个字节的空间,但是有时可能不能整除,所以要开N/8+1个字节的空间。

shiwei0813的博客 439

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

bitset的简单实现

M的博客 887

【C++】bitset位图的简单模拟实现及常见面试题

快速查找某个数据是否在一个集合中排序 + 去重求两个集合的交集、并集等操作系统中磁盘块标记数据是否在给定的整形数据中,结果是在或者不在,刚好是两种状态,那么可以使用一个二进制比特位来代表数据是否存在的信息,如果二进制比特位为1,代表存在,为0代表不存在。

m0_74774759的博客 427

位图bitset ,布隆过滤器详解及模拟实现[C++]

可以实现一个打印函数,便于检查我们上述代码的正确性,打印位图时遍历位图所包含的比特位进行打印即可,在打印位图的过程中可以顺便统计位图中位的个数count,将count与我们传入的非类型模板参数N进行比较,可以判断位图大小是否是符合我们的预期。我们这里可以大概估算一下,如果使用3个哈希函数,即k的值为3,l n 2 ln2ln2的值我们取0.7,那么 m mm 和 n nn 的关系大概是m = 4.3× n ,也就是布隆过滤器的长度应该是插入元素个数的5倍。类型开辟数组, 没有听说过开多少bit位的数组。

EQUINOX1的博客 222

【C++补充】第一弹---位图技术揭秘:内存优化与快速访问

位图相关面试题,位图的设计及实现,C++库中的位图 bitset,位图的模拟实现,位图的优缺点,位图相关考察题目~~~

小林熬夜学习编程的博客 2552

C++ 位图 bitset

N是一个非类型模板参数,表示这个。

Forward♞的博客 807

bitset(位图)的使用与模拟实现

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

平淡中造就不平凡 1347

31.位图bitset

位图概念 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景。通常是用来判断某个数据存不存在的 使用方式: #include #include using namespace std; int main() { bitset<10> bt; cout << bt << endl; cout <<"size:"&lt...

qq_43808700的博客 255
上一篇: 【 C++ 】开散列哈希桶的模拟实现
下一篇: 【 C++ 】哈希应用
.滄海难为水
博客等级 码龄4年 758粉丝 115原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值