boost dynamic_bitset

来源:互联网 发布:淘宝网小衫女 编辑:程序博客网 时间:2024/06/09 13:46

dynamic_bitset:
 c++98标准为处理二进制数值提供了两个工具:vector<bool>和bitset.
vector<bool>是对元素类型为bool的vector特化,内部并不真正存储bool值,而是以bit来压缩保存,使用代理技术来操作bit,造成的后果就是它很像容器,大多数情况下的行为与标准容器一致,但它不是容器,不满足容器的定义。
 bitset与vector<bool>类似,同样存储二进制位,但它的大小固定,而且比vector<bool>支持更多的位运算。
 vector<bool>和biset各有优缺点:vector<bool>可以动态增长,但不能方便地进行位运算,bitset则正好相反,可以方便地容纳的二进制做位运算,但不能动态增长。
 boost.dynamic_bitset的出现恰好填补了这两种之间的空白,它类似标准库的bitset,提供丰富的位运算,同时长度又是动态可变的。
#include <boost/dynamic_bitset.hpp>
using namespace boost;
 
 boost.dynamic_bitset几乎与std::bitset相同,包括接口和行为,唯一区别是boost.dynamic_bitset的大小是在构造函数中由参数指定的,而且运行时是动态可变的。

 注意,与vector<bool>和bitset一样,boost.dynamic_bitset不符合标准容器的定义,不是严格意义上的“容器”。

创建与赋值:
 boost.dynamic_bitset模板参数:
template<typename Block, typename Allocator>
Block指示以什么类型存储二进制位,必须是一个无符号整数,默认值unsigned long。
Allocator是类内部使用的内存分配器,默认是std::allocator<Block>

创建boost.dynamic_bitset对象方式:
 【1】不带参数构造函数创建该对象,可以在之后增长
 【2】传入参数指定大小,并赋值,像标准容器
 【3】从另一个对象拷贝
 【4】从01字符串构造(boost.dynamic_bitset与std::biset有相同缺陷,要求字符串必须是std::string,而不能是c字符串).
示范:
dynamic_bitset<> db1;
dynamic_bitset<> db2(10);
dynamic_bitset<> db3(0x16, BOOST_BINARY(10101));//使用BOOST_BINARY宏,构造编译期二进制数,没有运行时开销,较db4使用string临时变量的构造效率高
dynamic_bitset<> db4(string("0100"));
dynamic_bitset<> db5(db3);
dynamic_bitset<> db6;
db6 = db4;

cout<<hex<<db5.to_ulong()<<endl;
cout<<db4[0]<<db4[1]<<<db4[2]<endl;//001
 dynamic_bitset内部按照由高到低的顺序存储二进制位

容器:
 dynamic_bitset可以使用resize()成员函数在运行时调整容器大小,例如:
dynamic_bitset<> db;
db.resize(10,true);
cout<<db<<endl;
db.resize(5);
cout<<db<<endl;
 清空dynamic_bitset可以使用resize(0),但更应该调用clear()函数,它更快速。
 dynamic_bitset也提供与标准容器相同的size()和empty()函数
dynamic_bitset<> db(5, BOOST_BINARY(01110));
cout<<db<<endl;
assert(db.size() == 5);
db.clear();
assert(db.empty() && db.size() == 0);
 dynamic_bitset使用Block来存储二进制位,因此size()不能反映dynamic_bitset所占用的内存大小,dynamic_bitset提供num_blocks()返回所有二进制位占用的Block数量,即size()/sizeof(Block) * 8 +1,

 dynamic_bitset可以像vector那样使用push_back()向容器末尾追加一个值;
dynamic_bitset<> db(5, BOOST_BINARY(01110));
db.push_back(true); //db = 101001
 append()将整数转换为二进制位全部追加到dynamic_bitset末尾(最高位),这将使dynamic_bitset的大小增加一个Block的长度.
dynamic_bitset<> db(5, BOOST_BINARY(01110));
db.append(BOOST_BINARY(101);
assert(db.size() == sizeof(unsigned long)*8 + 5);
cout<<db<<endl;//0000000000000000000000000000010101001
位运算与比较运算:
 与vector<bool>相似,dynamic_bitset也运用了代理技术,重载了operator[],|等操作符,可以像普通数组那样访问其中的二进制位,而且能对二进制位或整个容器做任意位运算(|,^,~,<<等)。dynamic_bitset也同时提供了各种比较操作符,可以对两个dynamic_bitset对象进行各种比较运算.
 因此对dynamic_bitset对象的操作就如同操作两个普通的二进制数,只是不能做加减乘除运算。

dynamic_bitset<> db1(4, BOOST_BINARY(1010));
db1[0] &=1;
db1[0] ^=1;
cout<<db1<<endl;//1000
dynamic_bitset<> db2(4, BOOST_BINARY(0101));
assert(db1 > db2);
cout<<(db1 ^ db2 )<<endl;//1101
cout<<(db1 | db2 )<<endl;//1101

访问元素:
 dynamic_bitset还有数个成员函数用于测试或翻转二进制位.
 四个测试二进制位的函数:
 【1】test()函数检验第n位是否为1;
 【2】如果容器中存在二进制位1,那么any()返回true;
 【3】如果容器中不存在二进制位1,那么none()返回true;
 【4】count()函数统计容器中所有值为1的元素的数量.
示范:
dynamic_bitset<> db(4, BOOST_BINARY(0101));
assert(db.test(0) && !db.test(1));
assert(db.any() && !db.none());
assert(db.count() == 2);
有三个翻转二进制位的函数:
 【1】set()函数可以置全部或者特定位置为1或0;
 【2】reset*(可以置全部或者特定位置为0;
 【3】flip()可以反转全部或者特定位置的值。
这三个函数有两种重载形式,无参的版本操作dynamic_bitset的所有二进制位,带参的版本操作指定的二进制位。
示范:
dynamic_bitset<> db(4, BOOST_BINARY(0101));
db.flip();//翻转
assert(db.to_ulong() == BOOST_BINARY(1010));
db.set();//置所有位为1
assert(!db.none());
db.reset();//置所有位为0
assert(!db.any());
db.set(1, 1);//设置db[1]为值1
assert(db.count() == 1);//
 dynamic_bitset还提供了查找操作:
 【1】find_first从第0位置开始查找,返回第一个值为1的位置;
 【2】find_next(pos)则从第pos位置开始查找,返回第一个值为1的位置,如果找不到这样的值,返回npos;
 dynamic_bitset不是容器,不提供迭代器,故这两个查找函数法返回的不是迭代器对象,而是容器内二进制的索引值,其类型是内部类型定义size_type,即size_t,用法如下:
dynamic_bitset<> db(5, BOOST_BINARY(00101));
BOOST_AUTO(pos, db.find_first());//从最低位找
assert(pos == 0);
pos = db.find_next(pos);
assert(pos == 2);

类型转换:
 dynamic_bitset的成员函数to_ulong(),它可以直接把内部存储的二进制转换成一个类型为unsigned long的整数.
dynamic_bitset<> db(10, BOOST_BINARY(1010101));
cout<< db.to_ulong()<<endl;//85
 但to_ulong()的前提是dynamic_bitset内部存储的二进制位表示不能超过unsigned long的最大值(即std::numeric_limits<unsigned long>::max()),否则会转换失败,抛出std::overflow_error异常.
示范:先用append()为dynamic_bitset增加了一个整数,虽然整数值很小,但它为dynamic_bitset增加了32位的二进制(前面全是0),当再追加一个1位就超过unsigned long的上限。
db.append(10);    //追加一个整数
cout<<db.to_ulong()<<endl;//10325
db.push_back(1);          //再追加一个二进制位,超过ulong的上限 
cout<<db.to_ulong()<<endl;//抛出异常
 
 当dynamic_bitset无法转换成一个unsigned long表示的时候,可以使用自由函数void to_string()转换成一个标准字符串,它不会抛出异常(除非无法分配内存),to_string()把转换后的字符串通过参数传出,而不是以返回值的形式
string str;
to_string(db, str);
cout<<str<<endl;

集合操作:
 dynamic_bitset容纳的是01值,这使得它适合用于表示集合,dynamic_bitset支持集合的基本运算,如交集,并集和差集,但并没有提供专门的成员函数,因为这些集合运算都可以由位运算实现,如:operator& 和operator|对应于交集和并集.
 dynamic_bitset为子集运算实现了两个成员函数,is_subset_of和is_proper_subset_of,分别监测一个对象是否是另一个对象的子集或真子集,要求这两个检查的对象里的元素数量必须相等,否则会引发运行时断言异常。
示范:
dynamic_bitset<> db1(5, BOOST_BINARY(10101));
dynamic_bitset<> db2(5, BOOST_BINARY(10010));
cout<<(db1 | db2)<<endl;//并集10111
cout<<(db1 & db2)<<endl;//交集10000
cout<<(db1 - db2)<<endl;//差集00101
dynamic_bitset<> db3(5, BOOST_BINARY(101));
assert(db3.is_proper_subset_of(db1));//是真子集
dynamic_bitset<> db4(db2);//拷贝构造
assert(db4.is_subset_of(db2));//是子集
assert(!db4.is_proper_subset_of(db2));//不是真子集

综合运用:使用dynamic_bitset实现从2开始的整数区间筛法求质数.
#include <iostream>
#include <boost/dynamic_bitset.hpp>
using namespace boost;
using namespace std;
int main()
{
 int n;
 cin>>n;
 dynamic_bitset<> db(n);
 db.set();//使用set()置集合中所有位标准,进行筛选前的准备
 //筛选时,跳过dynamic_bitset里的0和1,因为它既不是质数也不是合数,使用find_next()来查找集合中的元素,运用筛选删除它的倍数
 for(dynamic_bitset<>::size_type i = db.find_next(1); i!= dynamic_bitset<>::npos; i = db.find_next(i))
 {
  for(dynamic_bitset<>::size_type j = db.find_next(i); j != dynamic_bitset<>::npos; j = db.find_next(j))
  {
   if (j %i == 0)
    db[j] = 0; //被整除,非质数
  }
 }

 for(dynamic_bitset<>::size_type i = db.find_next(2); i!= dynamic_bitset<>::npos; i = db.find_next(i))
  cout<<i<<", ";//输出质数
 cout<<endl;
 system("pause");
}

原创粉丝点击