C++ bitset类的使用
因为无知而学习,因为学习而更感无知。
在刷题过程中遇到不少的位操作,这里有必要学习一下C++ 内置的bitset类。欢迎各位指出文中的错误。
本文主要内容:
1. bitset类的函数使用
2. 自己实现的myBitset类
1. bitset类的使用
–代码主要参考《C++ Primer》
#include <bitset>//包含头文件,是标准库的头文件
#include <iostream>
#include <array>
using namespace std;
/*
在C++中,int 和long值范围一样,4Bytes
unsigned int 和unsigned long 取值范围一样,4Bytes
long long 占8个字节,有符号整型。
unsigned long long占8字节,无符号整型。
*/
//构造函数。bitset是一个类,类似于vector和array<int,n>
void constructionTset() {
//1. bitset<n> b;这里n必须是常量,b是对象。传入n代表对象b具有n位0、1。默认每一位均是0
bitset<8> b;//0000 0000
//2. bitset<n> b(u) b是unsigned long lnog 值低n位的拷贝。如果n大于unsinged long lnog的大小,则b中超出unsigned long lnog 的高位被置为0。如果n小于unsigned long lnog的大小,则对u从低位进行截取。
unsigned long long i = 0xbeef; //1011 1110 1110 1111
bitset<32> b1(i);//0000 0000 0000 0000 1011 1110 1110 1111;
bitset<8> b2(i);//1110 1111
int j = 1;
bitset<32> b3(j);//使用整型值来初始化bitset时,该整型值先被初始化为ull类型并当作位模式来处理。
//3. bitset<n> b(s,pos,m,zero,one) b是从string s从位置pos开始的m个字符的拷贝。s中的每一个字符只能包含'1' or '0'。如果s中包含其他字符,则会抛出invaild_argument异常。pos默认位置是0,m默认是string::npos。zero默认是0,one默认是1,都缺省不写。
string s = "11101111";
bitset<8> b4(s, 0, s.npos);//1110 1111
//0xbeef的二进制位序列位1011 1110 1110 1111
int k = 0xbeef;
bitset<13> b5(k);//1 1110 1110 1111
bitset<20> b6(k);//0000 1011 1110 1110 1111 高位补0
string s2 = "111110001010110";
bitset<16> b7(s2, 5, 4); //0000 0000 0000 0001 从s2[5]开始,到s2[5+4]
bitset<16> b8(s2, s2.size() - 4);//等价于b8(s2,s2.size()-4,s2.npos); 0000 0000 0000 0110
}
void OperatorTest() {
int i = 19960623;//0000 0001 0011 0000 1001 0011 0010 1111
bitset<32> b(i);
//1. bool any()const; b.any();如果b中有置位的二进制位,则返回true。即使判断b中是否存在1
cout << "any():" << b.any() << endl;//1
//2.bool all()const; 如果b中所有位均为1,则返回true
cout << "all():"<<b.all() << endl;//0
//3.bool none()const;如果b中不存在1,则返回true
cout << "none():" << b.none() << endl;//0
//4.输出b中置位的个数。即使统计b中具有多少个1
cout << "count():" << b.count() << endl;//12
//5.constexpr size_t size() const;范围b中的位数
cout << "size():" << b.size() << endl;//32
//6.bool test(size_t pos) const;如果pos位置是1,则返回true,否则返回false。位置是从0开始数起的
cout<<"test():"<<b.test(5)<<endl;
//7.set(pos,v);将b中pos位置的位设置为v。重载版本set()不传递任何参数的话,将所有位复位既是置为1
/*
b.set(0, 0);
cout << "test():" << b.test(0) << endl;//0
b.set();
b.flip();
cout << "test():" << b.test(0) << endl;//1
*/
//8.flip()将所有位取反。flip(size_t pos)将pos位取反。
//9.b[pos]如果pos位是1返回true,否则返回0
cout << "b[0]=" << b[0] << endl;//1
/*
10. b.to_ulong();返回unsigned long类型的数据
b.to_ullong();返回ull类型的数据
b.to_string(); 返回字符串
*/
cout <<"UL:" <<b.to_ulong() << endl;//unsigned long to_ulong()const
cout << "ULL:" << b.to_ullong() << endl;//19960623
cout << "string:" << b.to_string() << endl; //"00000001001100001001001100101111"
//11.os<<b;将b中二进制位打印为字符1或0,打印到流os;
//12.is>>b;从is读取字符存入b中,下一个字符不是1或0时,或是已经读入b.size()个位时,读取过程停止
cout << "b:" << b << endl;//通过重载<<实现
//13.reset(pos) 和reset();将pos位置为1 或者将所有位置为1
}
void test03() {
bitset<16> b(19960623);
cout << b;
}
int main() {
//OperatorTest();
test03();
return EXIT_SUCCESS;
}
2. myBitset类的实现
根据C++提供的标准类bitset函数的功能,使用vector辅助实现一个类,该类包含bitset的大多数功能。
#include <iostream>
#include <array>
#include <vector>
#include <string>
#include <functional>
#include <algorithm>
#include <fstream>
#include <climits>
#include <exception>
using namespace std;
template<size_t cap>
class myBitset final{
private:
vector<bool> vec;
public:
myBitset() {
vec.resize(cap, false);
};
myBitset(unsigned long long n) {//在传入参数时就隐式更改了形参类型
vec.resize(cap, false);
vector<bool> v = intToBinary(n);
if (v.size() > cap) {//要进行截取
for (int i = 0; i < cap; i++) {
vec[i] = v[i];
}
reverse(vec.begin(), vec.end());//翻转
}
else if(v.size()<=cap){
/*这个循环不需要,因为初始化vec时就初始化为false了
for (int i = 0; i < cap - v.size(); i++) {
vec[i] = false;
}
*/
reverse(v.begin(), v.end());
for (int i = 0; i < v.size(); i++) {
vec[cap - v.size()+i] = v[i];
}
}
}
myBitset(string s,size_t pos=0,size_t end=-1) {
vec.resize(cap, false);
if (end == -1) {
end = s.size();
}
end = end + pos;
exception e1("invaild_argument!");
exception e2("传入的参数有误!");
try {
if (pos<0 || pos >= s.size() || end==0) {
throw e2;
}
for (int i = pos; i <end; i++) {
if (s[i] == '1' || s[i] == '0')continue;
else throw e1;
}
}
catch (exception e) {
cout << e.what()<<endl;
return;
}
if (end - pos <= cap) {
for (int i = 0; i < cap - (end - pos); i++) {
vec[i] = false;//填充0
}
for (int i = cap - (end - pos), j = pos; i < cap; i++) {
if (s[j] == '1') {
vec[i] = true;
}
else if (s[j] == '0') {
vec[i] = false;
}
j++;
}
}
else if (end - pos > cap) {
for (int i = 0,j=pos; i < cap; i++) {
if (s[j] == '1') {
vec[i] = true;
}
else if (s[j] == '0') {
vec[i] = false;
}
j++;
}
}
}
template<size_t cap>
friend ostream& operator<<(ostream& out, myBitset<cap>& b);
bool operator[](size_t pos)const {
return vec[pos];
}
bool any()const {
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == true)return true;
}
return false;
}
bool all()const {
for (auto v : vec) {
if (v == false) {
return false;
}
}
return true;
}
bool none() const{
for (auto v : vec) {
if (v == true)return false;
}
return true;
}
size_t count()const {
int res = 0;
for (auto v : vec) {
if (v == true)res++;
}
return res;
}
constexpr size_t size() const {
return vec.size();
}
bool test(size_t pos) const{
exception e("位置越界!函数返回值无效。");
try {
if (pos > size()) {
throw e;
}
else {
return vec[pos];
}
}
catch (exception e) {
cout << e.what() << endl;
return false;
}
}
myBitset& set(size_t pos,bool val) {
exception e("位置越界!设置无效。");
try {
if (pos > size()) {
throw e;
}
else {
vec[pos] = val;
}
}
catch (exception e) {
cout << e.what() << endl;
}
return *this;
}
myBitset& set()noexcept {
for (auto v : vec) {
v = true;
}
return *this;
}
myBitset& reset()noexcept {
for (auto v : vec) {
v = ~v;
}
return *this;
}
myBitset& flip() {
for (int i = 0; i < vec.size(); i++) {
vec[i] = ~vec[i];
}
return *this;
}
myBitset& flip(size_t pos) {
vec[pos] = ~vec[pos];
return *this;
}
string to_string() noexcept {
string str(vec.size(),'0');
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == true) {
str[i] = '1';
}
}
return str;
}
unsigned long to_ulong() {
exception e("overflow_error!");
int index = -1;
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == true) {
index = i;
break;
}
}
try {
if (vec.size() - index > 32) {
throw e;
}
else {
auto fun = [&]()->unsigned long {
unsigned long res = 0;
for (int i = vec.size() - 1; i >= 0; i--) {
if (vec[i] == true) {
res += pow(2, vec.size() - 1 - i);
}
}
return res;
};
return fun();
}
}
catch (exception e) {
cout << e.what() << endl;
return LONG_MIN;
}
}
unsigned long long to_ullong() {
exception e("overflow_error!");
int index = -1;
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == true) {
index = i;
break;
}
}
try {
if (vec.size() - index > 64) {
throw e;
}
else {
auto fun = [&]()->unsigned long long {
unsigned long long res = 0;
for (int i = vec.size() - 1; i >= 0; i--) {
if (vec[i] == true) {
res += pow(2, vec.size() - 1 - i);
}
}
return res;
};
return fun();
}
}
catch (exception e) {
cout << e.what();
return LLONG_MIN;
}
}
};
//重写输出输出运算符时,只能采用全局函数的方式,因为不能再ostream和istream类中编写成员函数。将重载输入输出运算符和函数声明为友元函数。并且返回输入输出流对象,支持链式操作。
template<size_t cap>
ostream& operator<<(ostream& out, myBitset<cap>& b)
{
vector<bool> temp = b.vec;
for (int i = 0; i < temp.size(); i++) {
out << temp[i];
}
return out;
}
vector<bool> intToBinary(unsigned long long n) {
vector<bool> v;
while (n>0)
{
v.push_back(n%2);
n = n >> 1;
}
return v;
}
int main() {
myBitset<8> b1;
cout << "b1:" << b1 << endl;
myBitset<16> b2(19960623);//37679,因为发生了截断。
b2.test(20);//参数越界。
cout << b2.to_string() << endl;
cout << b2.to_ulong() << endl;
cout << b2.to_ullong() << endl;
//cout << b2 << endl;
//string s = "11101111";
//myBitset<16> b3(s, 4, 4);
//cout << b3;
return 0;
}