C++的bitset是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间。从整体效果来看,可以简单认为bitset中存放的就是一个无符号二进制整数。
一、bitset的定义和初始化
要使用bitset,首先需要引入头文件#include<bitset>
。虽然bitset也是模板类,但是和vector很不同的是,定义bitset变量的基本格式:bitset<n> bs;
,尖括号<>中是长度,并不是数据类型(bitset的元素只能是0或1,不存在数据类型一说)。
来看定义并初始化bitset的例子:
#include<iostream> #include<bitset> using namespace std; int main() { //没有参数,全部元素值为0 bitset<8> bs1; //bs1内容为{0,0,0,0,0,0,0,0} //通过无符号整数初始化bitset //按无符号整数对应的二进制数的每一位来初始化bitset,高位补0 bitset<16> bs2(255); //bitset(16) bs2(0xff); //255对应二进制11111111,二进制低位复制到bitset低位 //bs2内容为{1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0} //通过01字符串(string或者char数组均可)初始化bitset string s = "1101001"; bitset<10> bs3(s); //bitset<10> bs3(string("1101001")); //字符串高位复制到bitset低位(因为字符串对应的二进制数的低位在字符串的高位) //bs3内容为{1,0,0,1,0,1,1,0,0,0} //直接用cout输出bitset(按对应二进制数的形式输出,输出时高位在前,低位在后) cout<<bs1<<endl; //00000000 cout<<bs2<<endl; //0000000011111111 cout<<bs3<<endl; //0001101001 return 0; }
可以通过无符号整数来初始化bitset,会将无符号整数对应的二进制数的低位到高位依次复制到bitset的低位到高位。也可以通过“01”字符串来初始化bitset,会将字符串逆序内容依次复制到bitset的低位到高位。初始化时,如果bitset长度够长,那么在bitset高位补0。如果bitset长度不够,对于用无符号整数来初始化bitset,会截取无符号整数对应二进制数的低位;对于用字符串来初始化bitset,会截取字符串的前面部分。
二、元素访问
可以像数组那样使用[]
来获取bitset元素的值,也能对元素重新赋值,下标从0开始:
#include<iostream> #include<bitset> using namespace std; int main() { const int N = 16; bitset<N> bs(28); cout<<bs[0]<<" "<<bs[N-1]<<endl; cout<<bs<<endl; //正向遍历 for(int i=0;i<N;i++) cout<<bs[i]; cout<<endl; //反向遍历 for(int i=N-1;i>=0;i--) cout<<bs[i]; cout<<endl; bs[0] = bs[N-1] = 1; cout<<bs<<endl; return 0; }
三、成员函数
成员函数 | 功能 |
---|---|
bs.any() | 是否存在值为1的二进制位 |
bs.none() | 是否不存在值为1的二进制位(或者说,是否全部二进制位都为0) |
bs.size() | 位长,也就是初始化时指定的长度(返回值类型是size_t) |
bs.count() | 二进制位值为1的个数 |
bs.test(pos) | 测试pos处的二进制位是否为1 |
bs.set() | 全部二进制位的值设置为1 |
bs.set(pos) | pos位处的二进制位的值设置为1 |
bs.set(pos,v) | pos位处的二进制位的值设置为v |
bs.reset() | 全部二进制位的值设置为0 |
bs.reset(pos) | pos位处的二进制位的值设置为0 |
bs.flip() | 全部二进制位的值取反 |
bs.flip(pos) | pos处的二进制位的值取反 |
bs.to_ulong() | 返回将二进制转换为unsigned long的结果 |
bs.to_ullong() | 返回将二进制转换为unsigned long long的结果 |
bs.to_string() | 返回将二进制转换为字符串的结果 |
四、位运算
前面提到,可以简单认为bitset中存放的就是一个无符号二进制整数。bitset内部还重载了几乎所有的位运算符,因此bitset也能像普通整数那样进行位运算:
#include<iostream> #include<bitset> using namespace std; int main() { bitset<8> bs1(string("10101101")); bitset<8> bs2(string("10100010")); //判断相等(支持==和!=运算) if(bs1==bs2) cout<<"equal"<<endl; else cout<<"not equal"<<endl; //按位与运算 cout<<(bs1&bs2)<<endl; //按位或运算 cout<<(bs1|bs2)<<endl; //按位异或运算 cout<<(bs1^bs2)<<endl; //按位取反 cout<<(~bs1)<<" "<<(~bs2)<<endl; //移位运算 cout<<(bs1<<1)<<endl; //左移,低位补0 cout<<(bs1>>2)<<endl; //右移,高位补0 //位运算并自赋值 bs1 ^= bs2; cout<<bs1<<endl; bs1 >>= 3; cout<<bs1<<endl; return 0; }
五、经典例题
1.二进制十进制相互转换
需求:输出一个十进制数n转换为二进制。这里可以直接用十进制数初始化bitset,然后输出bitset即可(想办法不输出高位多余的0)。
#include<iostream> #include<bitset> using namespace std; int main() { int n; cin>>n; if(n<0) cout<<"-",n = -n; const int N = 32; bitset<N> bs(n); int i = N-1; //排除掉高位多余0 while(i>0 && !bs[i]) i--; for(;i>=0;i--) cout<<bs[i]; return 0; }
如何将二进制数转换成十进制呢?可以用“01”字符串初始化bitset,然后用成员函数to_ulong或者to_ullong来返回对应的无符号十进制数。
#include<iostream> #include<bitset> using namespace std; int main() { string s; cin>>s; bitset<64> bs(s); cout<<bs.to_ullong()<<endl; return 0; }
2.bitset作为标记数组
bitset的每个元素值只能是0或者1,占1个bit,可以将bitset用作标记“0-1”状态的“标记数组”,比起int数组要更节约存储空间。以前面的一个问题为例——数组例题——房间的门:
#include<iostream> #include<bitset> using namespace std; int main() { const int N = 100; bitset<N+1> bs; for(int i=1;i<=N;i++){ for(int j=i;j<=N;j+=i){ bs.flip(j); } } //门开着的房间的数量 cout<<bs.count()<<endl; //输出门开着的房间的编号 for(int i=1;i<=N;i++){ if(bs.test(i)) cout<<i<<" "; } return 0; }