C++(标准库):24---STL容器之(特殊容器bitset)

一、bitset概述

  • 标准库定义了bitset类,使得位运算使用更为容易,并且能够处理超过最长整型类型大小的位集合
  • bitset定义在头文件bitset中

二、定义和初始化bitset

  • 上图给出了bitset的构造方法
  • 低位与高位:
    • 二进制集合的起始位置(索引为0)称为低位,往后的称为高位
    • 注意,bitset的索引0从最右侧开始
  • bitset是一个类模板,类似于array类,具有固定的大小,且大小必须是一个常量表达式。当我们定义一个bitset时,需要声明它包含多少个二进制位:
std::bitset<32> bitvec(1U);  //U占32位。因此bitvec为32位;低位为1,其他位均为0

用unsigned值初始化bitset

  • 当我们使用一个整型值来初始化bitset时,此值会被转换为unsigned long long类型并被当作位模式来处理
  • 规则如下:
    • 如果bitset的大小大于一个unsigned long long中的二进制位数,则剩余的高位被置位0
    • 如果bitset的大小小于一个unsigned long long中的二进制位数,则只使用给定值中的地位,超出bitset大小的高位被丢弃
  • 例如:
//0xbeef为:1011 1110 1110 1111

//bitvec1比初始值小。高位被丢弃
std::bitset<13> bitvec1(0xbeef);  //二进制位序列为1 1110 1110 1111

//bitvec1比初始值大。高位被置位0
std::bitset<20> bitvec2(0xbeef);  //进制位序列为0000 1011 1110 1110 1111

//在64位机器上,long long 0ULL是64位的,因此~0ULL是64个1
std::bitset<128> bitvec3(~0ULL);  //0~63位为1,63~127位为0

std::cout << "bitvec1: " << bitvec1 << std::endl;
std::cout << "bitvec2: " << bitvec2 << std::endl;
std::cout << "bitvec3: " << bitvec3 << std::endl;

从一个string初始化bitset

  • 我们可以从一个string或一个字符数组指针来初始化bitset
  • 注意(重点):当使用字符串表示数时,字符串中下标最小的字符对应高位,下标最大的字符对应低位
  • 例如:
std::bitset<32> bitvec4("1100"); //1100
std::cout << "bitvec4 : " << bitvec4 << std::endl;

  • 我们也可以使用string的子串来初始化bitset。例如:
std::string str("1111111000000011001101");
std::bitset<32> bitvec5(str, 5, 4);           //1100
std::bitset<32> bitvec6(str, str.size() - 4); //1101

std::cout << "bitvec5 : " << bitvec5 << std::endl;
std::cout << "bitvec6 : " << bitvec6 << std::endl;

三、bitset的操作

  • 操作大概分为两类:
    • 一类返回bitset的信息。例如count、size、all、any、none等
    • 另一类用来设置bitset。例如set、reset、flip。这些函数都是重载的
  • 例如:
std::bitset<32> bitVec(1U);      //32位,低位为1,剩余位为0

bool is_set = bitVec.any();      //true,因为有1被置位
bool is_not_set = bitVec.none(); //false,因为有1被置位
bool all_set = bitVec.all();     //false,因为有1被置位

size_t onBits = bitVec.count();  //返回1
size_t sz = bitVec.size();       //返回31

bitVec.flip();                   //反转bitvec中的所有位
bitVec.reset();                  //将所有位复位
bitVec.set();                    //将所有位复位
  • 成员flip、set、reset和test允许我们读写指定位置的位,例如:
std::bitset<32> bitVec(1U);     //32位,低位为1,剩余位为0

int i = 5;
bitVec.flip(0);                 //翻转第1位          
bitVec.set(bitVec.size() - 1);  //置位第1位
bitVec.set(0, 0);               //复位第1位
bitVec.reset(i);                //复位第i位
bitVec.test(0);                 //返回false,因为第1位是复位的
  • 下标运算符对const属性进行了重载:
    • const版本的下标运算符将所在位的值返回给bool,如果该位为1返回true,该位为0返回falase
    • 非const版本返回bitset定义的一个特殊类型,允许我们操纵指定位的值
std::bitset<32> bitVec(1U);   //32位,低位为1,剩余位为0

bitVec[0] = 0;                //将第1位复位 
bitVec[31] = bitVec[0];       //将最后一位设置为与第1位一样
bitVec[0].flip();             //翻转第1位
~bitVec[0];                   //等价操作,也是翻转第1位
bool b = bitVec[0];           //将bitVec[0]的值转换为bool类型

提取bitset的值(to_ulong、to_ullong)

  • to_ulong和to_ullong操作都返回一个值,保存了与bitset对象相同的位模式
  • 只有当bitset的大小<=对应的大小(to_ulong为unsigned long,to_ullong为unsigned long long)时,才能使用这两个操作
  • 例如:
//在64位机器上,long long 0ULL是64位的,因此~0ULL是64个1
std::bitset<128> bitvec3(~0ULL);  //0~63位为1,63~127位为0
	
unsigned long ulong = bitvec3.to_ulong();
std::cout << "ulong = " << ulong << std::endl;
  • 上面程序的运行结果如下:

bitset的IO运算符

  • 输入运算符(>>):
    • 从一个输入流读取字符,保存到一个临时的string对象中
    • 直到读取的字符数达到bitset对应的大小时,或是遇到不是1或0的字符时,或是遇到文件尾或输入错误时,读取过程才停止
    • 读取过程结束之后,立即使用临时string对象来初始化bitset
    • 如果读取的字符数小于bitset的大小,与往常一样,高位被置位0
  • 输出运算符(<<):
    • 打印一个bitset对象中的位模式
  • 例如:
std::bitset<16> bits;
std::cin >> bits;
std::cout << "bits: " << bits << std::endl;

演示案例

  • 现在我们有一个程序:假设班级中有30个学生,老师每周都会对学生进行一次检测,检测的结果分为通过和不通过两种。我们使用一个unsigned long来表示,在任何机器上unsigned long都至少为32位,因此可以使用每一位来代替一个学生
  • 我们下面先使用最普通的位运算来完成这个功能
bool status;
unsigned long quizA = 0;    //此值被当作位集合使用
quizA |= 1UL << 27;         //指出第27个学生通过了检测
status = quizA&(1UL << 27); //检查第27个学生示范通过了检测
quizA &= ~(1UL << 27);      //第27个学生为通过检测
  • 我们使用bitset来完成上面同样的工作 
bool status;
	
std::bitset<30> quizB; //每个学生分配一位,所有位初始化为0
quizB.set(27);         ///指出第27个学生通过了检测
status = quizB[27];    //检查第27个学生示范通过了检测
quizB.reset(04);       //第27个学生为通过检测
发布了1594 篇原创文章 · 获赞 1190 · 访问量 57万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/105484604
今日推荐