C++库中的BitSet用法详解及源码介绍

  (1) bitset数据结构体定义 
 bitset定义在对应的bitset.h头文件内,结构如下: typedef struct {  size_t *bits;  size_t nbits; } bitset; 
字段bits类似于记录保存比特的数组(通过一连串的size_t类型存储空间),而nbits记录该数组内的比特元素数目。  为了更好的理解这个结构体的字段元素,只要看其对应的初始化函数bitset_init就行了。在该函数内,传入的参数nbits表示初始化分配的bit元素个数,而对于bits指向的空间分配必须是size_t类型的整数倍(size_t 是为了方便系统之间的移植而定义的,在32位系统上 定义为 unsigned int,在64位系统上 定义为 unsigned long,更准确地说法是 在 32位系统上是32位无符号整形,在 64位系统上是64位无符号整形,size_t一般用来表示一种计数,比如有多少东西被拷贝等。)因此BITSET_USED宏就是起这个(计算nbits是size_t类型长度的多少整数倍)作用。BITSET_USED宏内涉及到的另外一个宏BITSET_BITS用于计算size_t类型长度(CHAR_BIT定义在/usr/include/limits.h头文件内,例如为“# define CHAR_BIT 8”,表示一个字节有多少比特)。  举个例子,如下图所示(在32位机器上),当参数nbits为25时,虽然25小于一个size_t类型长度(32),但仍需分配一个size_t类型长度的内存空间。 
 
(2) bitset数据结构体操作 
几个函数都比较简单,倒是几个宏值得注意,下面列出各函数和宏的功能: bitset_reset函数功能:将比特元素全部重置为0。 bitset_free函数功能:释放结构体。 
bitset_clear_bit函数功能:设置某位比特元素为0。 bitset_set_bit函数功能:设置某位比特元素为1。 
bitset_test_bit函数功能:测试某位比特元素是否为1,为1返回真(1),为0返回假(0)。  
宏BITSET_MASK: 获得某位为1的mask码 
比如第0位为1的mask码:0000 0000 0000 0000 0000 0000 0000 0001 比如第3位为1的mask码:0000 0000 0000 0000 0000 0000 0000 1000 pos从0开始 
#define BITSET_MASK(pos) \ 

 ( ((size_t)1) << ((pos) % BITSET_BITS) )  
宏BITSET_WORD: 

根据pos获取在set中占到的对应size_t元素 #define BITSET_WORD(set, pos) \  ( (set)->bits[(pos) / BITSET_BITS] ) 

问题的提出

欲编程控制城市道路交通信号灯。每个信号灯一般有红、绿、黄三种灯色。如果用1表示灯亮,0表示灯灭,那么某时刻,信号灯的状态可以用三个0、1二进制位记录,要改变某个灯的状态,只需改变相应位的0、1值即可,换句话,即针对某个位位操作。(一般高级语言处理数据的最小单位只能是字节

应用

(1)控制硬件时,常涉及到打开/关闭特定的位或查看它们的状态。

(2)当一组信息中的每个元素只有两种状态时,使用位操作。比如,一个信号灯就是一组0、1信息集,三个灯色即三个元素,每个元素(每个灯)只有0和1两种状态。

实现方法

两种:直接位操作(从C语言继承而来);使用标准库提供的bitset类型操作。

(1)   位操作符(6个:表1

表1 位操作符

操作符

~

<< 

>> 

&

^

|

功能

按位求反

左移

右移

按位与

按位异或

按位或

注意:位操作时,要考虑其他位的状态。

1) 按位与(&)

功能:将两个操作数对应的每一位分别进行逻辑与操作,比如:3&5:00000001(先将3和5转换为二进制形式,然后按位与)

应用:可以将操作数中的若干位置0(其他位不变),或者取操作数中的若干指定位。

Exa1:将char型变量a的最低位置0。

a=a&0376

Exa2:假设c是char型变量,a是int变量,下列语句可取出a的低字节,存入c中。

c=a&0377

2) 按位或(|)

功能:将两个操作数对应的每一位分别进行逻辑与操作或操作,比如:3|5:00000111

应用:可以将操作数中的若干位置1(其他位不变)。

Exa3:将int型变量a的低字节置1。

a=a|0xff

3) 按位异或(^)

功能:将两个操作数对应的每一位分别进行异或,规则:对应位相同,运算结果为0;对应位不同,运算结果为1。

应用:将操作数中的若干指定位翻转。如果使某位与0异或,结果是该位的原值;如果使某位与1异或,结果与该位原来的值相反。例如:要使01111010低四位翻转,可以与00001111进行异或。

4)其他位操作运算符参考相关文献。

Exa4:某时刻信号交叉口信号灯状态模拟

思路:信号灯三种灯色二进制编码为(只需3位):100(红灯亮,八进制形式为04)、010(绿灯亮,八进制形式为02)、001(黄灯亮,八进制形式为01),再增加一位表示方向,1表示东西向,0表示南北向。计算机基本存储单位为字节,所以用一个字节(8位)来存储信号灯状态。从低位起3至1位,对应红、绿、黄三种灯色,第4位表示方向。数据结构如下(只用低4位):

 

 

 

 

控制方向

红灯

绿灯

黄灯

 

实现:用变量trafficLight表示信号灯状态值(8位),如果想让某方向信号灯绿灯亮,基本步骤:先让第4位值不变(方向不变),其他位都为0(和1000进行与操作);然后让绿灯位为1(和010进行或操作)。

#include<iostream>

using namespace std;

int main()

{

    unsigned inttrafficLight=014;//注意:前缀0表示该数据为八进制形式(二进制:00001100),当前值为东西向红灯亮

   unsigned int bit1=010;//010为1000的八进制形式

   unsigned int bit2=02;//02为二进制010的八进制形式

   trafficLight=trafficLight&bit1;//信号灯当前值与1000进行与操作,保持第4位值不变(方向不变),其他灯色位为0

   trafficLight=trafficLight|bit2;//绿灯位为1,其他位不变

   cout<<"信号灯当前状态为:"<<oct<<trafficLight<<endl;

   system("pause");

   return 0;

}

注意:对于位操作符,由于系统不能确保如何处理其操作数的符号位,所以强烈建议使用无符号整型操作数。

(2)   使用标准库提供的bitset类型

Exa5:假设某班有30个学生,计算机老师做了一次测试,只有及格和不及格两种成绩,对每个学生用一个二进制位来记录成绩及格或不及格。(为调试方便,将学生数该为5)

分析:由于学生人数较多,当需要修改或查看第27位同学的成绩时,使用位操作相当麻烦。

#include<iostream>

#include<bitset>     //首先包含bitset标准库

using namespace std;

int main()

{

    bitset<5> score;

  unsigned int i=0;

  cout<<"pleaseinput pass num:";//

  while(cin>>i &&i!=5)

  score.set(i);

  cout<<score<<endl;

  //system("pause");

  return 0;

}

注意:一般而言,标准库提供的bitset操作更直接、更容易阅读和书写。而且,bieset对象的大小不受unsigned数的位数限制。通常来说,bitset优于整型数据的低级直接位操作。

补充:标准库bitset类型

要使用bitset类,必须包含相关的头文件。

#include<bitset>

然后,定义bitset对象且初始化,最后执行相应的操作。

bitset对象的定义和初始化

格式1:bitset<30> student;

30个二进制位,下标从0开始,初值全为0,student为对象名(变量名),其中,30和student两个参数用户可以改。

格式2:bitset<32> student2(0xffff);

0xffff为十六进制数,0至15位值为1,16至31位值为0。其中,32、student2和0xffff三个参数用户可以改。

注意:bitset类的缺点,不能动态调整长度。(若需动态调整,可使用vector类)

bitset对象上的操作

操作

功能

b.any()

b中是否存在置为1的二进制位?  返回值为bool类型(true,false)

b.none()

b中不存在置为1的二进制位吗?  返回值为bool类型

b.count()

b中是置为1的二进制位位数

b.size()

b中二进制位的个数

b[n]

访问b中第n位

b.test(n)

b中第n位是否为1               返回值为bool类型

b.set()

把b中所有位都置为1

b.set(n)

把b中第n位置为1

b.reset()

把b中所有位都置为0

b.reset(n)

把b中第n位置为0

b.flip()

把b中所有位按位取反

b.flip(n)

把b中第n位取反


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值