C++ bitset(位图)的模拟实现
文章目录
- 一、bitset接口总览
- 二、bitset模拟实现
- 1. 构造函数
- 2. set、reset、flip、test
- 3. size、count
- 4. any、none、all
- 5. 打印函数
- 三、完整代码
一、bitset接口总览
| 成员函数 | 功能 |
|---|---|
set | 设置指定位或所有位为1(即设置为“已设置”状态) |
reset | 清空指定位或所有位,将其设为0(即设置为“未设置”状态) |
flip | 反转指定位或所有位的状态。如果位是0,则变为1;如果位是1,则变为0 |
test | 获取指定位的状态。如果位是1,则返回true;如果位是0,则返回false |
count | 获取被设置为1的位的个数(即“已设置”的位的数量) |
size | 获取位图可以容纳的位的总数。这通常指的是位图数组的总大小(以位为单位) |
any | 如果有任何一个位被设置为1(即至少有一个位是“已设置”状态),则返回true;否则返回false |
none | 如果没有位被设置为1(即所有位都是“未设置”状态),则返回true;否则返回false |
all | 如果所有位都被设置为1(即所有位都是“已设置”状态),则返回true;否则返回false |
#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
namespace qi
{template <size_t N>class bitset{private:std::vector<int> _bits;public:bitset();void set(size_t pos);void reset(size_t pos);void flip(size_t pos);size_t size();size_t count();bool test(size_t pos);bool any();bool none();bool all();void Print(); //打印函数};
}
二、bitset模拟实现
1. 构造函数
在创建位图的时候我们需要根据所给的参数N,来构造一个N位的位图,并将该位图的所有位全部设置为0。
这里我们使用vector来做底层容器,一个int有32个比特位,但是非类型模板参数N,不一定总是32的整数倍,所以我们在构造的时候得先计算一下需要几个int。
例如,假如我们要建立一个50个比特位的位图,就需要两个int大小,共64个比特位,使用前50个比特位,后14个舍弃不用就好。
因此我们用式子 N/32+1来计算需要几个int。

具体实现也比较简单,直接调用vector的resize函数即可。
bitset()
{_bits.resize(N / 32 + 1, 0);
}
2. set、reset、flip、test
set,根据下标pos,把位图的该位置设置成1
- 计算出该位位于第 i 个整数的第 j 个比特位。
- 将1左移 j 位后与第 i 个整数进行或运算即可。

void set(size_t pos)
{assert(pos < N);int i = pos / 32;//第几个整数,算出来的i相当与下标int j = pos % 32;//第i个整数的第j个比特位,j也相当于下标//注意下标都是从0开始的_bits[i] |= (1 << j);
}
reset根据下标pos,将下标为pos位置的位图设置成0
- 计算出该位位于第 i 个整数的第 j 个比特位。
- 将1左移 j 位再整体反转后与第 i 个整数进行与运算即可。

void reset(size_t pos)
{assert(pos < N);int i = pos / 32;//第几个整数,算出来的i相当与下标int j = pos % 32;//第i个整数的第j个比特位,j也相当于下标//注意下标都是从0开始的_bits[i] &= (~(1 << j));//左移后要取反在&
}
flip根据下标pos反转指定下标的比特位
- 计算出该位位于第 i 个整数的第 j 个比特位。
- 将1左移 j 位后与第 i 个整数进行异或运算即可。

void flip(size_t pos)
{assert(pos < N);int i = pos / 32;//第几个整数,算出来的i相当与下标int j = pos % 32;//第i个整数的第j个比特位,j也相当于下标//注意下标都是从0开始的_bits[i] ^= (1 << j);
}
test检测下标pos处的位图是否为1,为1返回true,否则返回false
- 计算出该位位于第 i 个整数的第 j 个比特位。
- 将1左移 j 位后与第 i 个整数进行与运算得出结果。
- 若结果非0,则该位被设置,否则该位未被设置。

bool test(size_t pos)
{assert(pos < N);int i = pos / 32;//第几个整数,算出来的i相当与下标int j = pos % 32;//第i个整数的第j个比特位,j也相当于下标//注意下标都是从0开始的if (_bits[i] & (1 << j)){return true;}return false;
}
3. size、count
size用于返回位图一共有多少位,也就是非类型模板参数N的值
直接返回N就好
size_t size()
{return N;
}
count用于计算该位图中有多少位是1,返回值是位图中1的个数
统计二进制中1的个数的方法如下:
- 将原数 n 与 n - 1 进行与运算得到新的 n 。
- 判断 n 是否为0,若 n 不为0则继续进行第一步。
- 如此进行下去,直到 n 最终为0,此时该操作进行了几次就说明二进制中有多少个1。
因为该操作每进行一次就会消去二进制中最右边的1,如图:

size_t count()
{size_t count = 0;for (auto e : _bits){int num = e;while (num){num &= (num - 1);++count;}}return count;
}
4. any、none、all
any表示位图中只要有一个1那就返回true,否则返回false
判断方式比较简单,每一个整数的所有比特位,只要有一个为1,那该整数就肯定不等于0,所以,我们可以遍历所有整数,只要有一个整数不等于0,那就说明有1,返回true,否则所有整数都是0,没一个1,返回false
bool any()
{for (auto e : _bits){if (e != 0){return true;}}return false;;
}
none表示位图中如果全是0,没一个1那就返回true,否则返回false
其实和any是对立的,如果any为假,说明全为0,说明none为真,所以none中只需将any的结果取反后返回就好了。
bool none()
{return !any();
}
all表示,全为1返回true,否则返回false
判断过程分为两步:
- 先检查前n-1个整数的二进制是否为全1。
- 再检查最后一个整数的前N%32个比特位是否为全1。
需要注意的是,如果位图没有包含最后一个整数的全部比特位,那么最后一个整数的二进制无论如何都不会为全1,所以在判断最后一个整数时应该只判断位图所包含的比特位。
bool all()
{size_t n = _bits.size();//先检查前n-1个整数for (size_t i = 0; i < n - 1; i++){if (~_bits[i] != 0) //取反后不为全0,说明取反前不为全1return false;}//再检查最后一个整数的前N%32位for (size_t j = 0; j < N % 32; j++){if ((_bits[n - 1] & (1 << j)) == 0) //该位未被设置return false;}return true;
}
5. 打印函数
为了验证bitset对象的正确性,我们可以编写一个自定义的打印函数,该函数将遍历bitset中的每一位,并打印出其状态(0或1)。同时,这个函数还可以统计并返回bitset中实际被设置(即值为1)的位的数量,并将这个数量与bitset的模板参数(即预期的大小)进行比较,以确认bitset的大小是否符合预期。
#include <iostream>
#include <bitset>
using namespace std;// 自定义打印函数,用于打印bitset并统计1的个数
template<size_t N>
void printAndVerifyBitset(const bitset<N>& bs) {size_t count = 0; // 用于统计1的个数cout << "Bitset: ";```cpp
//打印函数
void Print()
{int count = 0;size_t n = _bits.size();//先打印前n-1个整数for (size_t i = 0; i < n - 1; i++){for (size_t j = 0; j < 32; j++){if (_bits[i] & (1 << j)) //该位被设置std::cout << "1";else //该位未被设置std::cout << "0";count++;}}//再打印最后一个整数的前N%32位for (size_t j = 0; j < N % 32; j++){if (_bits[n - 1] & (1 << j)) //该位被设置std::cout << "1";else //该位未被设置std::cout << "0";count++;}std::cout << " " << count << std::endl; //打印总共打印的位的个数
}
三、完整代码
#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
namespace qi
{template <size_t N>class bitset{private:std::vector<int> _bits;public:bitset(){_bits.resize(N / 32 + 1, 0);}void set(size_t pos){assert(pos < N);int i = pos / 32;int j = pos % 32;_bits[i] |= (1 << j);}void reset(size_t pos){assert(pos < N);int i = pos / 32;int j = pos % 32;_bits[i] &= (~(1 << j));}void flip(size_t pos){assert(pos < N);int i = pos / 32;int j = pos % 32;_bits[i] ^= (1 << j);}size_t size(){return N;}size_t count(){size_t count = 0;for (auto e : _bits){int num = e;while (num){num &= (num - 1);++count;}}return count;}bool test(size_t pos){assert(pos < N);int i = pos / 32;int j = pos % 32;if (_bits[i] & (1 << j)){return true;}return false;}bool any(){for (auto e : _bits){if (e != 0){return true;}}return false;;}bool none(){return !any();}bool all(){size_t n = _bits.size();for (int i = 0; i < n - 1; i++){if (~_bits[i] != 0){return false;}}for(int i = 0; i < N % 32; i++){if ((_bits[n - 1] & (1 << i)) == 0) //该位未被设置return false;}return true;}//打印函数void Print(){int count = 0;size_t n = _bits.size();//先打印前n-1个整数for (size_t i = 0; i < n - 1; i++){for (size_t j = 0; j < 32; j++){if (_bits[i] & (1 << j)) //该位被设置std::cout << "1";else //该位未被设置std::cout << "0";count++;}}//再打印最后一个整数的前N%32位for (size_t j = 0; j < N % 32; j++){if (_bits[n - 1] & (1 << j)) //该位被设置std::cout << "1";else //该位未被设置std::cout << "0";count++;}std::cout << " " << count << std::endl; //打印总共打印的位的个数}};
}
相关文章:
C++ bitset(位图)的模拟实现
文章目录 一、bitset接口总览二、bitset模拟实现1. 构造函数2. set、reset、flip、test3. size、count4. any、none、all5. 打印函数 三、完整代码 一、bitset接口总览 成员函数功能set设置指定位或所有位为1(即设置为“已设置”状态)reset清空指定位或…...
Llama 3.2:利用开放、可定制的模型实现边缘人工智能和视觉革命
在我们发布 Llama 3.1 模型群后的两个月内,包括 405B - 第一个开放的前沿级人工智能模型在内,它们所产生的影响令我们兴奋不已。 虽然这些模型非常强大,但我们也认识到,使用它们进行构建需要大量的计算资源和专业知识。 我们也听到…...
解决R语言bug ‘sh‘ is not recognized as an internal or external command
安装源码包‘httr2’ trying URL ‘https://cran.rstudio.com/src/contrib/httr2_1.0.5.tar.gz’ Content type ‘application/x-gzip’ length 230632 bytes (225 KB) downloaded 225 KB installing source package ‘httr2’ … ** package ‘httr2’ successfully unpacked…...
记一次Mac 匪夷所思终端常用网络命令恢复记录
一天莫名奇妙发现ping dig 等基础命令都无法正常使用。还好能浏览器能正常访问,,,, 赶紧拿baidu试试^-^ ; <<>> DiG 9.10.6 <<>> baidu.com ;; global options: cmd ;; connection timed out; no serve…...
2024最新!!Java后端面试题(4)看这一篇就够了!!!!
七、异常 throw 和 throws 的区别? throw用来显式地抛出一个异常,而throws则用于在方法声明中指明该方法可能抛出的异常。简单来说,throw是抛出异常的实际动作,throws是告知调用者这个方法可能会抛出哪些异常的声明。 final、f…...
springboot整合sentinel和对feign熔断降级
一、准备 docker安装好sentinel-dashboard(sentinel控制台),参考docker安装好各个组件的命令启动sentinel-dashboard,我的虚拟机ip为192.168.200.131,sentinel-dashboard的端口为8858 二、整合sentinel的主要工作 在…...
遗传算法与深度学习实战——使用进化策略实现EvoLisa
遗传算法与深度学习实战——使用进化策略实现EvoLisa 0. 前言1. 使用进化策略实现 EvoLisa2. 运行结果相关链接 0. 前言 我们已经学习了进化策略 (Evolutionary Strategies, ES) 的基本原理,并且尝试使用 ES 解决了函数逼近问题。函数逼近是一个很好的基准问题&…...
HttpServletRequest简介
HttpServletRequest是什么? HttpServletRequest是一个接口,其父接口是ServletRequest;HttpServletRequest是Tomcat将请求报文转换封装而来的对象,在Tomcat调用service方法时传入;HttpServletRequest代表客户端发来的请…...
c++开发之编译curl(安卓版本)
为了在 Android 上编译支持 OpenSSL 的 libcurl,你需要手动编译 libcurl 和 OpenSSL,并确保它们能够在 Android 的交叉编译环境中正常工作。以下是详细的步骤说明。 1. 安装必要工具 在编译之前,确保你已经安装了以下工具: And…...
QT+ESP8266+STM32项目构建三部曲三--QT从环境配置到源程序的解析
一、阿里云环境配置 大家在编写QT连接阿里云的程序之前,先按照下面这篇文章让消息可以在阿里云上顺利流转 QTESP8266STM32项目构建三部曲二--阿里云云端处理之云产品流转-CSDN博客文章浏览阅读485次,点赞7次,收藏4次。创建两个设备ÿ…...
Web APIs 5:Window对象(BOM)+本地存储
Web APIs 5(BOM:Window对象本地存储) 1.BOM(浏览器对象模型)(后面几个对象都为BOM对象) BOM对象包含:navigator、location、document(DOM对象)、history、screenBOM是一个全局对象,即JS中的顶…...
神经网络(四):UNet图像分割网络
文章目录 一、简介二、网络结构2.1编码器部分2.2解码器部分2.3完整代码 三、实战案例 论文链接:点击跳转 一、简介 UNet网络是一种用于图像分割的卷积神经网络,其特点是采用了U型网络结构,因此称为UNet。该网络具有编码器和解码器结构&#…...
Java 编码系列:注解处理器详解与面试题解析
引言 在上一篇文章中,我们详细探讨了 Java 注解的基本概念、自定义注解、元注解等技术。本文将继续深入探讨 Java 注解处理器(Annotation Processor),介绍如何编写注解处理器,并结合大厂的最佳实践和面试题详细解析其…...
C语言 | Leetcode C语言题解之第441题排列硬币
题目: 题解: class Solution { public:int arrangeCoins(int n) {return (int) ((sqrt((long long) 8 * n 1) - 1) / 2);} };...
Linux noVNC远程桌面(xfce)部署
一、安装 VNC 服务器和桌面环境 Notebook实验 常用vnc服务 VNC (Virtual Network Computing) 是一种远程桌面协议,可以让你通过网络访问服务器的图形界面。 TurboVNC:专为图形密集型应用设计,尤其适合 3D 可视化和高分辨率图像的远程传输…...
【网络安全】身份认证
1. 身份认证 1.1 定义 身份认证(Authentication)是确认用户身份的过程,确保只有授权的用户才能访问系统或资源。它通常涉及验证用户提供的凭证,如密码、生物特征或其他识别标志。 1.2 重要性 身份认证是信息安全的第一道防线&…...
LeetCode - #124 二叉树中的最大路径和(Top 100)
文章目录 前言1. 描述2. 示例3. 答案关于我们前言 本题为 LeetCode 前 100 高频题 我们社区陆续会将顾毅(Netflix 增长黑客,《iOS 面试之道》作者,ACE 职业健身教练。)的 Swift 算法题题解整理为文字版以方便大家学习与阅读。 LeetCode 算法到目前我们已经更新到 123 期…...
Java:插入排序
目录 排序的概念 插入排序 直接插入排序 哈希排序 排序的概念 排序:所谓的排序,就是使一串记录,按照某个或某些关键字的大小,递增或递减的排列起来的操作。 稳定性:假定在待排序的记录序列中,存在多个…...
How FAR ARE WE FROM AGI?(ICLR AGI Workshop 2024)概览
关注B站可以观看更多实战教学视频:hallo128的个人空间 How FAR ARE WE FROM AGI?官网 How FAR ARE WE FROM AGI?(ICLR AGI Workshop 2024) 该研讨会将于2024年5月11日在奥地利维也纳以混合模式举行,作为 ICLR 2024年会议的一部…...
leetcode刷题day33|动态规划Part02(62.不同路径、63. 不同路径 II、 343.整数拆分、96.不同的二叉搜索树)
62.不同路径 机器人从(0 , 0) 位置出发,到(m - 1, n - 1)终点。 动规五部曲 1、确定dp数组(dp table)以及下标的含义 dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
