← 目录 / 第十一章 · STL 标准模板库 / 11.12 bitset

11.12 bitset 位集

专门处理二进制位的容器——每个元素只占 1 个 bit,处理位运算时极其高效。

本页目录

bitset 是一个专门处理二进制位的容器。它的每一个元素只占 1 个 bit(而不是 1 个字节),处理位运算时极其高效。使用前需引入 <bitset> 头文件。

bitset<8> b("10101010");8 个 bit,从左到右依次是第 7 位到第 0 位
1
0
1
0
1
0
1
0
7
6
5
4
3
2
1
0
每个格子只占 1 bit,而不是普通 bool 数组里 1 个字节(8 bit)。8 个元素的 bitset 实际只占用 1 个字节的内存,vector<bool> 也有类似的压缩存储,但 bitset 的位运算接口更直接好用。
💡
和数组的区别:bitset<N> 的大小 N 必须是编译期常量,定义好之后不能再改变长度——这点和 array 类似,跟可以动态变长的 vector 不同。
11.12.1 定义与初始化
C++ · bitset 的几种创建方式
1#include <bitset>
2using namespace std;
3
4int main()
5{
6 bitset<8> b1; // 全部初始化为 0:00000000
7 bitset<8> b2("10101010"); // 用字符串初始化:10101010
8 bitset<8> b3(10); // 用整数初始化:10 的二进制是 00001010
9
10 cout << b2 << endl; // 直接 cout 输出:10101010
11
12 return 0;
13}
📌
bitset 可以直接用 cout 输出,会自动打印成二进制字符串的形式——不需要手动转换,这点比手写位运算方便很多。
11.12.2 常用操作

bitset 提供了一套读、改单个 bit 的成员函数,比手写 (n >> i) & 1 之类的位运算表达式更直观。

函数功能返回值 / 效果
.count()统计有多少位是 1size_t
.test(i)查询第 i 位是 0 还是 1bool
.set(i)把第 i 位设为 1
.set(i, v)把第 i 位设为 v(0 或 1)
.reset(i)把第 i 位设为 0
.flip(i)把第 i 位翻转(0↔1)
.flip()把全部位翻转
.any()是否至少有一位是 1bool
.none()是否全部位都是 0bool
.size()返回 bitset 的总位数(即 N)size_t
.to_string()转换成字符串string
.to_ulong()转换成 unsigned longunsigned long
C++ · 查询与修改单个 bit
1bitset<8> b("10101010");
2
3cout << b.count() << endl; // 4——有 4 个 1
4cout << b.test(0) << endl; // 0——第 0 位是 0
5cout << b.test(1) << endl; // 1——第 1 位是 1
6
7 b.set(0, 1); // 把第 0 位设为 1
8 b.reset(2); // 把第 2 位设为 0
9 b.flip(); // 全部翻转(0 变 1,1 变 0)
⚠️
bitset 的下标 从右往左数,从 0 开始——和 vector、数组的下标方向相反。b[0] 是最右边(最低位),不是最左边。打印出来的字符串顺序是"高位在左",但 .test() / .set() 的下标是从右边的低位开始数的,刚学的时候容易搞反。
11.12.3 位运算

bitset 支持和整数一样的位运算符 &(与)、|(或)、^(异或)、~(取反),写法和数学符号一致,但作用在每一位上:

a & c(按位与)
1
1
0
0
&
1
0
1
0
=
1
0
0
0
a | c(按位或)
1
1
0
0
|
1
0
1
0
=
1
1
1
0
a ^ c(按位异或)
1
1
0
0
^
1
0
1
0
=
0
1
1
0
C++ · bitset 的位运算
1bitset<8> a("1100"), c("1010");
2
3cout << (a & c) << endl; // 按位与:00001000
4cout << (a | c) << endl; // 按位或:00001110
5cout << (a ^ c) << endl; // 按位异或:00000110
🎯
为什么要用 bitset 做位运算?普通 int 最多 32 / 64 位,bitset 可以开到几千甚至几万位,并且 & / | / ^ 这些运算在底层是按"机器字长"批量处理的(比如 64 位一次),比逐位循环判断快得多。常用于状态压缩 DP、筛法优化(如埃氏筛配合 bitset 标记)等场景。
11.12.4 完整使用示例
C++ · bitset 综合示例
1#include <iostream>
2#include <bitset>
3using namespace std;
4
5int main()
6{
7 bitset<8> b("10101010"); // 8位二进制:10101010
8 cout << b << endl; // 输出:10101010
9 cout << b.count() << endl; // 输出:4——有几个 1
10 cout << b.test(0) << endl; // 输出:0——第 0 位是 0
11 cout << b.test(1) << endl; // 输出:1——第 1 位是 1
12
13 b.set(0, 1); // 把第 0 位设为 1
14 b.reset(2); // 把第 2 位设为 0
15 b.flip(); // 全部翻转(0 变 1,1 变 0)
16
17 // 位运算
18 bitset<8> a("1100"), c("1010");
19 cout << (a & c) << endl; // 按位与:1000
20 cout << (a | c) << endl; // 按位或:1110
21 cout << (a ^ c) << endl; // 按位异或:0110
22 return 0;
23}
📋 bitset 常用操作速查表

把本节出现过的方法按用途归类汇总,写代码时可以直接当参考卡用。

方法 / 写法分类作用
bitset<N> b定义定义 N 位、全为 0 的 bitset
bitset<N> b("...")定义用 0/1 字符串初始化
bitset<N> b(x)定义用整数 x 的二进制初始化
b[i]访问访问第 i 位(从右往左,从 0 开始)
.test(i)查询第 i 位是否为 1
.count()查询有多少位是 1
.any() / .none()查询是否有 1 / 是否全为 0
.size()查询总位数 N
.set(i) / .set(i,v)修改第 i 位设为 1 / 设为 v
.reset(i) / .reset()修改第 i 位设为 0 / 全部清零
.flip(i) / .flip()修改第 i 位翻转 / 全部翻转
& / | / ^ / ~位运算与 / 或 / 异或 / 取反
<< / >>位运算整体左移 / 右移
.to_string()转换转成 string
.to_ulong() / .to_ullong()转换转成 unsigned (long) long
🎯
什么时候用 bitset?需要大量、高频做位运算的场景:状态压缩 DP(用每一位表示一个状态是否被选中)、筛素数时标记合数、用位运算加速集合的交并差运算等。如果只是存几个布尔开关,普通 bool 变量或数组反而更直观。