位图

bitset

Posted by Marlin on August 2, 2025

位图

原理

用bit组成的数组来存放值,用bit状态1、0代表存在、不存在,取值和存值操作都用位运算。

限制是必须为连续范围且不能过大。好处是极大的节省空间,因为1个数字只占用1个bit的空间。

常用操作

对位图内元素的操作

  • 增:set(num) // 把num加入到位图
  • 删:reset(num) // 把num从位图中删除
  • 改:flip(num) // 取反num的bit位置
  • 查:test(num) // 查询num是否在位图中

位图之间的操作

  • 交:& // 按位与
  • 并:| // 按位或
  • 异或:^ // 按位异或
  • 取反:flip() // 按位取反
  • 统计:count() // 统计1的个数
  • 交换:swap() // 交换两个位图
  • 字符串:to_string() // 转化为字符串

实现

此处使用vector<int>来模拟位图,每个int表示32位,用&|^操作来操作位。

创建

初始化位图的大小,默认所有位都为0。只支持

1
2
vector<int> set((n + 31) / 32); // n位的位图(向上取整得到int数组的个数)
bitset<n> a; // n位的位图

增加(set)

1
2
set[num / 32] |= (1 << (num % 32)); // 把num的bit位置为1
a.set(num); // 将num加入位图

删除(reset)

1
2
set[num / 32] &= ~(1 << (num % 32)); // 把num的bit位置为0
a.reset(num); // 从位图中删除num

修改(flip)

1
2
set[num / 32] ^= (1 << (num % 32)); // 取反num的bit位置
a.flip(num); // 取反num

查询(test)

1
2
3
4
if(set[num / 32] & (1 << (num % 32))) // 第num位是否为1
    cout << num << "存在" << endl;
if(a.test(num)) // num是否在位图中
    cout << num << "存在" << endl;

运算

1
2
3
4
bitset<10> b(a); // 复制位图
bitset<10> c = a & b; // 位与
bitset<10> d = a | b; // 位或
bitset<10> e = a ^ b; // 位异或

遍历

1
2
3
4
5
6
7
8
for(int i = 0; i < n; i++){ // 遍历位图
    // 输出第i位
    cout << set[i / 32] & (1 << i % 32) << " ";
}

for(int i = 0; i < a.size(); i++){
    cout << a[i] << " ";
}

统计

1
2
bitset<10> g(a); // 复制位图
int count = g.count(); // 统计1的个数

交换

1
swap(a, b); // 交换位图

其他

1
2
3
bitset<10> j(a); // 复制位图
j.flip(); // 按位反转位图
j.to_string(); // 转化为字符串