C++ bitset(位图)的介绍和使用


一、bitset的介绍

1. 位图的引入

面试题

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】

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

单从方法上来说这两种方法都是可以的,但是从内存上来说,这里有40亿个整数,换算一下就相当于16G,也就是说要操作这些数据的话需要占用16G的内存,内存消耗是很大的,所以从内存上来看,这两种方法都是不合适的。
所以我们采用第三种方法来解决这个问题:

  1. 位图解决

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

在这里插入图片描述
无符号整数总共有 2 32 2^{32} 232个,因此记录这些数字就需要 2 32 2^{32} 232个比特位,也就是512M的内存空间,内存消耗大大减少。

2. 位图的概念

  1. 定义:位图是一种紧凑型数据结构,用于表示一个固定大小的集合或序列中的元素状态(存在或不存在)。它通常用于处理一组整数值或布尔值,例如集合操作、数据筛选和计数等应用场景。
  2. 工作原理:位图通过使用位数组来表示集合中的元素状态,每个元素对应一个位(bit),从而实现高效的空间和时间性能。位图通过一系列位数组(通常使用unsigned char或unsigned int类型的数组)来表示一组元素的状态。数组中的每一位(bit)表示集合中的一个元素的存在与否。
  3. 特点
    • 高效的空间利用率:位图在表示大范围的数据时非常紧凑,每个元素只需要一个位。
    • 快速的集合操作:位图支持高效的并集、交集和差集操作,这些操作可以通过位运算来实现。
    • 快速的存在检查:位图可以快速检查某个元素是否存在于集合中,通过索引直接访问位数组。
    • 固定大小:位图通常适用于固定大小的集合。如果要表示的集合范围不固定,可能需要额外的空间。
    • 不适合稀疏数据:位图在表示稀疏数据时可能浪费大量空间,因为空闲的元素仍然会占用位数组的空间。

3. 位图的应用场景

  1. 快速查找某个数据是否在一个集合中。
  2. 求两个集合的交集、并集等。
  3. 操作系统中磁盘块标记。
  4. 内核中信号标志位(信号屏蔽字和未决信号集)。

二、bitset的使用

1. 定义方式

bitset有三种定义方式。

  • 第一种:定义一个N个比特位的,初始值全为0的位图,这里的N是一个正整数,比如我们创建一个8个比特位的全为0的位图:
bitset<8> a;  //00000000

在这里插入图片描述

  • 第二种:构建一个位图,并根据所给的初始值,初始化位图的前几位。
bitset<8> a(9);  //0000 1001

在这里插入图片描述

  • 第三种:利用01字符串初始化位图的前n位
bitset<8> a(string("0111001"));  //00111001

在这里插入图片描述

2. 成员函数

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

使用示例:

在这里插入图片描述

#include <iostream>
#include <bitset>
using namespace std;

int main()
{
	bitset<8> bs;
	bs.set(2); //设置第2位
	bs.set(4); //设置第4位
	cout << bs << endl; //00010100
	
	bs.flip(); //反转所有位
	cout << bs << endl; //11101011
	cout << bs.count() << endl; //6

	cout << bs.test(3) << endl; //1

	bs.reset(0); //清空第0位
	cout << bs << endl; //11101010

	bs.flip(7); //反转第7位
	cout << bs << endl; //01101010

	cout << bs.size() << endl; //8

	cout << bs.any() << endl; //1

	bs.reset(); //清空所有位
	cout << bs.none() << endl; //1

	bs.set(); //设置所有位
	cout << bs.all() << endl; //1
	return 0;
}

3. 运算符重载

1. bitset中输入输出的使用

bitset中对>><<进行了重载,所以我们可以直接使用cincout对位图进行输入和输出

#include <iostream>
#include <bitset>
using namespace std;

int main()
{
	bitset<8> bs;
	cin >> bs; //10110
	cout << bs << endl; //00010110
	return 0;
}

在这里插入图片描述
2. bitset中运算符的使用

bitset容器中,不仅基本的赋值运算符(=)和一些关系运算符(==!=)被重载,还对一些复合赋值运算符(&=|=^=<<=>>=)和单目运算符(~)进行了重载。这使得我们可以直接使用这些运算符来对bitset对象(即位图)进行各种操作,如位的赋值、比较、逻辑运算、位移以及取反等。

例如,以下代码展示了如何使用这些运算符:

#include <iostream>
#include <string>
#include <bitset>
using namespace std;

int main() {
    bitset<8> bs1(string("10101010"));
    bitset<8> bs2(string("10101010"));
    
    // 使用复合赋值运算符右移bs1
    bs1 >>= 1;
    cout << bs1 << endl; // 输出: 01010101
    
    // 使用复合赋值运算符进行位或操作
    bs2 |= bs1;
    cout << bs2 << endl; // 输出: 11111111
    
    // 使用单目运算符取反
    // 注意:这里未直接展示,但可以通过 bs2 = ~bs2; 来实现
    
    return 0;
}

在这里插入图片描述

3. bitset中位运算符的使用

bitset容器还重载了三个位运算符(&|^),允许我们直接对两个bitset对象进行按位与、按位或、按位异或操作。

以下是示例代码:

#include <iostream>
#include <string>
#include <bitset>
using namespace std;

int main() {
    bitset<8> bs1(string("10101010"));
    bitset<8> bs2(string("01010101"));
    
    // 使用位运算符
    cout << (bs1 & bs2) << endl; // 输出: 00000000
    cout << (bs1 | bs2) << endl; // 输出: 11111111
    cout << (bs1 ^ bs2) << endl; // 输出: 11111111(因为bs1和bs2在每个位上都是相反的)
    
    return 0;
}

在这里插入图片描述

4. bitset中[ ]运算符的使用

bitset容器还重载了[ ]运算符,允许我们直接通过索引来访问或修改bitset中指定位置的位。

以下是示例代码:

#include <iostream>
#include <string>
#include <bitset>
using namespace std;

int main() {
    bitset<8> bs(string("00110101"));
    
    // 使用[ ]运算符访问和修改位
    cout << bs[0] << endl; // 输出: 1(因为索引从0开始,所以访问的是最右边的位)
    bs[0] = 0; // 修改最右边的位为0
    cout << bs << endl; // 输出: 00110100
    
    return 0;
}

在这里插入图片描述

通过这些示例,我们可以看到bitset容器提供了丰富的运算符支持,使得对位图的操作既方便又高效。

bitsetC++标准库中的一个类,用于表示固定大小的位集合。它可以用来进行位运算和位操作。对于bitset的交集操作,可以使用位运算符&来实现。假设有两个bitset对象bitset1和bitset2,可以使用以下代码计算它们的交集: ```cpp bitset<32> bitset1; // 假设bitset1是一个32位的bitset对象 bitset<32> bitset2; // 假设bitset2是一个32位的bitset对象 bitset<32> intersection = bitset1 & bitset2; // 使用位运算符&计算交集 int count = intersection.count(); // 计算交集中为1的位的个数 ``` 上述代码中,bitset1和bitset2是两个位集合,通过使用位运算符&计算它们的交集。交集的结果存储在intersection中。可以使用count()函数来计算交集中为1的位的个数。请注意,bitset的大小需要在创建对象时指定,上述代码中假设bitset的大小为32位。 #### 引用[.reference_title] - *1* [BitSet---最快求交集差集等的类](https://blog.csdn.net/Fire_Sky_Ho/article/details/123855704)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【C++bitset(位图)的使用](https://blog.csdn.net/sjsjnsjnn/article/details/128519935)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

争不过朝夕,又念着往昔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值