位操作
为操作有两种方式,C风格以及C++风格。
1. C风格的位操作使用了一系列的位操作运算符,如下:
操作符
|
功能
|
用法
|
~
|
按位非
|
~expr
|
<<
|
左移
|
expr1
|
>>
|
右移
|
expr1
|
&
|
按位与
|
expr1
|
^
|
按位异或
|
expr1
|
|
|
按位或
|
expr1
|
&=
|
按位与赋值
|
expr1
|
^=
|
按位异或赋值
|
expr1
|
|=
|
按位或赋值
|
expr1
|
2 .C++风格的位操作使用了C++标准库中的bitset类,包含在“bitset”头文件中。
操作
|
功能
|
用法
|
Test(pos)
|
Pos位是否为1
|
a.test(4)
|
Any()
|
任意位是否为1
|
a.any()
|
None()
|
是否没有位为1
|
a.none()
|
Count()
|
值是1的位的个数
|
a.count()
|
Size()
|
位元素的个数
|
a.size()
|
[pos]
|
访问pos位
|
a[4]
|
Flip(pos)
|
反转pos位
|
a.flip(4)
|
Flip()
|
反转所有位
|
a.flip()
|
Set()
|
将所有位置为1
|
a.set()
|
Set(pos)
|
将pos位置为1
|
a.set(4)
|
Reset()
|
将所有位置为0
|
a.reset()
|
Reset(pos)
|
将pos位置为0
|
a.reset(4)
|
Bitset对象有三种初始化方法。
b) bitset<32> bitvec; //系统默认每一位置零
c) bitset<32> bitvec(unsigned int); //用一个无符号的参数初始化
d) bitset<32> bitvec(string); //用一个代表0和1集合的字符串初始化
类型转换
1. 隐式转换
a) 混合类型表达式中,宽数据类型为目标转换类型。
b) 不同类型赋值表达式中,被赋值类型为目标转换类型。
c) 传递给函数调用时,函数形参类型为目标转换类型。
d) 函数返回表达式时,函数返回类型为目标转换类型。
2. 算数转换
算数转化在遵循隐式转换的第一条之前,会将所有宽度小于整形的类型,如short,bool以及枚举类型等提升为整型(intergeral promotion)。
3. 强制转换
使用cast-name <type> (expression) 语句转换。C++标准库提供了一组cast-name,用于不同用途的转换(可参考相关书籍)。
注意:强制转换是及其容易引起程序错误的根源之一,尤其是在指针类型的强制转换过程中。因为强制转换屏蔽了编译器的类型检查功能,使得某一指针可能指向其他类型而引发程序灾难,因此要尽量避免使用。
抽象容器类型
在c++标准库中提供了多种抽象容器类型。根据容器元素的数据结构可以分为顺序容器和关联容器两大类。
1. 顺序容器:拥有单一类型元素的集合。标准库中,顺序容器包括向量(vector),链表(list)以及队列(deque)。三者的主要区别在于所支持的元素添加与删除的方式。向量(vector)支持从尾部添加元素,队列(deque)对首部元素的添加提供了特殊支持。而链表(list)则是元素添加自由性最打的顺序容器,它支持任意位置的元素添加与删除。
2. 关联容器:元素关联了两个不同类型的数据,分别成为“键(key)”和“值(value)”。“值”存储了用户数据类型,而“键”则存储了改元素的查询标记。因此,关联容器提供了对一个元素的存在与否的查询,以及提供了有效获取该元素的方法。C++标准库中的关联容器类型主要包括“映射(map)”和“集合(set)”两种。
关于vector的一些用法
1. 容量与长度。为了提高效率,vector的实际工作方式并不是在添加每个元素时都动态增长,而是在初始化时分配一些预留的空间用来储存添加的元素,而容量正是表征了vector在下一次增长之前做能够容纳的元素个数。而长度则是当前vector中已经存在的元素的个数。
2. 初始容量。在一个空的vector被定义时,长度和容量都为零。当第一个元素被插入时长度增加为1,而系统会自动的根据元素的数据类型而将容量设定为一个大于一的默认值。我们也可以手动指定vector的长度和容量。在初始化时,我们可以利用vector的构造函数来显示的指定vector的长度和元素的初始值,例如:
vector <int> ivec(24,0);
定义了长度为24,元素初始值为0的vector对象。Vector对象的容量是利用成员函数
Reserved(int capacity)来实现的,比如我们指定刚才定义的vector对象容量为256。
ivec.reserve(256);
3. 迭代器(iterator)。尽管vector不能在任意位置插入元素,但是它却提供了访问任意元素的方法,这一方法正是利用迭代器(iterator)实现的。迭代器(iterator)是一个指向vector元素的指针,vector的成员函数begin()和end()分别返回了指向vector对象首和尾的两个iterator,因此我们可以通过偏执量来计算所要访问元素的iterator,从而方便的访问元素。
4. 拷贝构造。vector的构造函数提供了利用一对iterator来拷贝构造一个新的对象实例。例如:vector<int> ivec2(it1,it2);
其中it1和it2分别指向ivec1中的两个元素。则ivec2就成功拷贝it1和it2之间的部分(包括it1和it2)。
5. 元素的插入。
Push_back():在尾部插入元素。
Insert(vector<typename>::iterator iter,Val):iter是指向某一元素的指针,Val是要插入的值。这里要重点提出的是,插入的元素位于iter所指向的元素之前的。然而,值得注意的是vector有一对成员函数begin()和end(),返回类型为vector<typename>::iterator。尽管两个函数看起来相似,但是返回结果却有微妙的差别。begin()返回的是指向vector对象首元素的iter,而end()返回的却是最后一个元素的下一个元素。也就是说,end()返回的虽然是一个vector对象元素的指针,但指针所指向的单元格所存储的东西确实随机的,试图打印*end()时会出错,而*begin()却是可以打印的。 因此,其实push_back(Val)与insert(end(),val)是等价的。
Insert()还有一些其他形式的重载函数:
Insert(iter,iter1,iter):在iter的位置之前插入iter1和iter2之间的元素。
Insert(iter,num,val):在iter位置插入num个相同的元素val。
5. 元素的删除。erase()方法,具体方法跟insert()类似。