STL学习(14):bitset容器(位图)

因为C是一种“接近硬件”的语言,但C语言并没有固定的二进制表示法。BitSet可以看作是二进制位的容器,并提供了位的相关操作函数。

//(1)构造、赋值函数
bitset();
bitset(const bitset&)		;//拷贝构造函数
bitset(unsigned long val)	;//由无符号长整形数构建位容器
bitset(const string& str,size_t pos = 0, size_t n = -1);//由字符串创建位容器
bitset& operator=(const bitset&);//赋值操作
//(2)逻辑运算操作(与、或、非)
bitset& operator&=(const bitset&);
bitset& operator|=(const bitset&);
bitset& operator^=(const bitset&);
bitset& operator<<=(size_t);
bitset& operator>>=(size_t);
bitset operator<<(size_t n) const;
bitset operator>>(size_t n) const;
bitset operator&(const bitset&, const bitset&);
bitset operator|(const bitset&, const bitset&);
bitset operator^(const bitset&, const bitset&);
//(3)其他操作函数
string toString()		;//位容器内容转化成字符串,方便显示
size_t size() const		;//返回位容器大小
size_t count() const	;//返回设置1位个数
bool any() const		;//是否有位设置1
bool none() const		;//是否没有位设置1
bool test(size_t n) const	;//测试某位是否为1		
bool operator[](size_t n) const     ;//随机访问位元素
unsigned long to_ulong() const      ;//若没有溢出异常,返回无符号长整形数
bitset& set()		;//位容器所有位置1
bitset& flip()		;//位容器所有位翻转
bitset& reset()		;//位容器所有位置0
bitset& set(size_t n, int val = 1)  ;//设置某位为1或0,缺省1
bitset& reset(size_t n);// 	 ;//复位某位为0
bitset flip(size_t n);	 ;//翻转某位

定义位变量简单示例。

#include <iostream>
#include <string>
#include <bitset>
using namespace std;
void main()
{
	bitset<5> s1;    //会初始化一个至少具有5 bit的内存空间
	cout << "初始内存空间内容:" << s1.to_string() << endl;
	cout << "位容器空间(size):" << s1.size() << "\t置1个数(count):" << s1.count() << endl;

	s1.set(2, true);        //将第2位置1
	cout << "第2位置1后[set(2,true)]";
	cout << "	内存空间内容:" << s1.to_string() << endl;

	s1[3]=1; //另一种设置位方式,相当于数组表示
	cout << "第3位置1后[s1[3]=1]";
	cout << "	内存空间内容:" << s1.to_string() << endl;

	s1.set();
	cout << "所有位置1后[s1.set()]";
	cout << "	内存空间内容:" << s1.to_string() << endl;

	bitset<16> s2(65535);
	cout << "通过长整形数建立位容器:" <<s2.to_string() << endl;

	bitset<5> s3("1111101", 2, 5);
	cout << "通过字符串建立位容器:" << s3.to_string() << endl;
}

(1)结合结果体会size()和count()函数区别,set无参、有参函数区别,以及可以用[ ]随机访问位容器的某一位。同时思考一下reset无参、有参函数区别,flip无参、有参函数区别。

(2)当用长整形数建立位容器时,范围应在[0,)范围内,若位容器设置位数N不足以容纳长整形数,则仅截取假想已是二进制数的低N位。例如:bit<2> s4(13), 由于13二进制表示是1101,而容器仅两位,从低位开始填充,位容器内容为01。

(3)当用字符串建立位容器bitset(const string& str,size_t pos = 0, size_t n = -1)含义是:从字符串第pos位置字符开始,截取n个字符填充位容器,缺省设置是填充全字符串。但要注意字符串只能包含“1”或“0”字符,不能有其它字符。如“10101”正确,而“12345”错误。

位操作函数简单示例

#include <iostream>
#include <string>
#include <bitset>
using namespace std;
void main()
{
	bitset<5> s1("01011");
	bitset<5> s2("10010");    
	cout << "s1:" << s1.to_string() << "\t";
	cout << "s2:" << s2.to_string() << endl;
	s1 &= s2;		//结果修改了s1
	cout << " s1&=s2: " << s1.to_string() << endl;
	
	bitset<5> s3("01011");
	bitset<5> s4("10010");    
	bitset<5> s5 = s3 & s4;//与后结果赋值给s5,s3及s4不变
	cout << "s3:" << s3.to_string() << "\t";
	cout << "s4:" << s4.to_string() << endl;
	cout << " s5=s3&s4: " <<s5.to_string() << endl;
	cout << " 原s3: " << s3.to_string() << endl;
}

(1)本示例主要区分&=、&操作符的差别。&=操作符完成与操作同时,修改了第1个操作数。&操作符完成与操作,并不修改原操作数。其实从原型定义上也可以看出来:bitset& operator&=(const bitset&)返回当前位容器对象引用,因此当前位容器对象内容可能已发生了变化;bitset operator&(const bitset&, const bitset&)返回位容器对象的拷贝,且传入的两个与操作位容器对象类型是const,因此原容器内容一定不发生变化。依此类推,可知|, |=, ^, ^=, <<, <<=, >>, >>=的功能差别。

(2)若两个位容器对象进行各种操作,必须保证位容器大小相同,示例中容器大小均是5,所以可以进行操作。但如果bitset<5> s1, bitset<6> s2, 则s1, s2不能进行各种操作。

综合操作示例

编制功能类统计学生每月出勤天数。

分析:若每月都按31天计算,学生有两种状态:要么出勤,要么缺席。故采用bitset位向量来描述是最节省空间的,每月31天状态只用31位,不到4个字节就描述清楚了,

#include <iostream>
#include <string>
#include <bitset>
#include <vector>
using namespace std;

template<size_t N>
class MyAttend
{
	int month;	//月份
	bitset<N> b;//出勤位容器
public:
	MyAttend(int month, string strAttend):
		month(month),b(strAttend)
	{
	}
	int GetMonth() {return month;}
	int GetAttendDays() {return b.count();}
};

class Student
{
	string name;			//某同学
	vector<MyAttend<31> > v;//出勤集合 
public:
	Student(string name)
	{
		this->name = name;
	}
	void Add(MyAttend<31>& m)//添加某月出勤信息
	{
		v.push_back(m);
	}
	void ShowAttendDays()	//显示学生每月出勤情况
	{
		cout << "姓名:" << name << endl;
		cout << "月份\t出勤天数" << endl; 
		for(int i=0; i<v.size(); i++)
		{
			MyAttend<31>& m = v.at(i);
			int month = m.GetMonth();
			int days = m.GetAttendDays();
			cout << month << "\t" << days << endl;
		}
	}
};

void main()
{
	Student stud1("zhang"); //定义zhang同学

	string s1 = "1111100111110011111001111100111";//1月份出勤串 
	string s2 = "1111100111110011111001111100";//2月份出勤串
	MyAttend<31> m1(1, s1);
	MyAttend<31> m2(2, s2);
	stud1.Add(m1); //添加zhang同学1月份出勤信息
	stud1.Add(m2); //添加zhang同学2月份出勤信息	
	stud1.ShowAttendDays();//显示zhang同学出勤信息
}

已知n个整形数组,长度都是10,且元素都在[1,20]之间,且均递增排列,无重复数据。试利用bitset压缩这些数组,并存入文件中。

分析:假设一个整形数组{1,2,3,4,5,6,7,8,9,10},若按正常方式存入文件,共有10*4=40字节。根据要求特点可用一个20位的bitset容器保存某个数组。若数组中某位值是5,则把位容器第5位置1,依此类推。20位相当于2.5字节,与原先40字节相比,降低了16倍。但是文件操作中最小单位是字节,无法读写2.5字节,因此位容器选择24位大小,这样读写操作就正好是3个字节了。

#include <iostream>
#include <fstream>
#include <bitset>
using namespace std;

template<size_t N>
class MyNum
{
public:
	bitset<N> b;
public:
	void Set(int ary[], int nSize)//把整形数组压缩成位容器
	{
		b.reset();		//复位位容器
		for(int i=0; i<nSize; i++)
		{
			b.set(ary[i]-1, 1);
		}
	}
};

void main()
{
	int a[6][10]={{1,2,3,4,5,6,7,8,9,10},{1,3,4,5,6,7,8,9,10,12},
				{2,4,6,8,10,13,15,18,19,20},{1,5,6,8,9,10,12,14,18,20},
				{3,6,7,10,14,15,16,17,18,19},{1,6,8,9,10,12,15,17,18,19}};

	ofstream out("d:\\data.txt");	
	MyNum<24> m;
	for(int i=0; i<6; i++)
	{
		m.Set(a[i], 10);
		out.write((char *)&m.b, 3);
		cout << i << "\t"; 
	}
	out.close();
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值