c++定义了许多高级的抽象数据类型。之所以说这些标准库类型是更高级的,是因为其中反映了更复杂的概念;之所以说它们是抽象的,是因为我们在使用时不需要关心它们是如何表示的,只需要知道这些抽象数据类型支持哪些操作就可以了。
两种最重要的标准库类型是string和vector,string类型支持长度可变的字符串,vector可用于保存一组制定类型的对象。
先介绍一下string类型:
首先它有几个构造函数:
string s1;// 默认构造函数,s1空串。
string s2(s1);//
string s3(“value”);//将s3初始化位一个字符串字面值的副本。
string s4(n,'c'); //将s4初始化为字符'c'的n个副本。
读入string的一个用法:
while(cin>>s1);
可以循环读入s1。
getline(cin,s1);第一个参数是一个输入流对象,第二个参数是一个string对象。
它也可以被如上使用:
while(getline(cin>>s1))
getline的返回值是一个istream参数,所以可以被while判断。
size()成员函数从逻辑上讲似乎应该返回整型值,或者一个unsig类型,但事实上,size操作返回的是一个string::size_type类型的值,由此可见,string是一个类类型。实际上,这个size_type的定义与unsigned具有相同的含义,而且可以保证足够大,至于怎么设计的,这就不是咱们应该知道的了。。。
string对象的操作:
两个string对象 s1+=s2,作用就是将s2连接到s1的末尾。
string s1("HELLO"),s2="WORLD";
string s3=s1+','+s2+"\n";
s3输出为 HELLO,WORLD(回车)
但是如果你一不小心,可能就会犯点错误:
string s4=“HELLO”+’,‘;//error : each + has string opeand;
string s5=s1+','; // OK
从这个例子可以看出,要想在字符串之间进行”+“运算,+号左右两边必须要有一个string对象。
再举一个对string对象进行操作的函数:
string str("something");
for(string::size_type ix=0;ix!=str.size();ix++)
cout<<str[ix]<<endl;
从这里可以看出,size_type类型的值可以用下标,之前已经提到,size_type类型的值和unsigned类型的值类似,因为在使用下标索引string对象时,必须保证索引值“在上下界范围内”,而这两种类型的值可以保证索引值不小于0,因此,在使用这两种类型作为索引值的时候,只需要考虑它是否小于string长度即可。
标准库vector类型:
vector是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。和string对象一样,标准库将负责管理与存储元素相关的内存,我们把它称作 容器 ,这是因为他可以包含其他对象,但是一个容器中所有的对象必须是同一个类型的。在使用vector之前,必须包含<vector>头文件。它的实质是一个类模板。
vector对象的使用:
vector<T> v1;// vector 保存类型为T的对象,并且使用默认构造函数,vector为空。
用一个例子来讲如何基本的使用vector:
string word;
vector<string> text;
for(vector<int>::size_type ix=0;ix!=text.size();++ix)
text[ix]=0; 将vector全部置为0
注意,下标操作不能插入元素!!!
vector<int> ivec; //empty vector
for(vector<int>::size_type ix=0;ix!=text.size();++ix)
ivec[ix]=ix; //disaster: ivec has no elements
上述代码试图对一个空vector对象进行插入元素,可vector是一个空的,这样做可能会造成灾难性的后果,正确的使用方法应该是这样:
for(vector<int>::size_type ix=0;ix!=text.size();++ix)
ivec.push_back(ix);
介绍完vector,下面就是和它紧密相连的迭代器了。
除了对vector对象使用下标来访问vector对象之外,标准库还提供了另外一种访问元素的方法:使用迭代器。注意,所有的标准库类型都定影了相应的迭代器类型,而只有少部分容器支持下表操作。所以,c++中更倾向于使用迭代器而不是下标访问容器元素。
每个标准库容器类型都定义了一个iterator成员,这里的iterator类型和迭代器的实际类型含义相同。
下面介绍如何使用迭代器:
vector <int> ::iterator iter=ivec.begin();
begin操作返回ivec[0]地址,而由end操作返回的是指向迭代器的“末端元素的下一个”,通常指 超出末端迭代器 。如果vector为空,则begin和end返回同一个迭代器。
对迭代器可以使用解引用,但是end操作返回的迭代器不能使用解引用。
对迭代器使用++操作符是使其指向下一个元素。
每一种容器类型还定义了一种const_iterator的类型,该类型只能用于读取容器内的元素, 但不能改变其值。
例如,如果text是vector<string>类型,程序员想要遍历它,输出每个元素,可以这样写程序:
// use const_itreator because we won't not change the elements
for(vector<string>::const_iterator iter=text.begin();\
iter!=text.end();++iter)
cout<<*iter<<endl;
不要把const_iterator和const 的iterator混淆,const_iterator对象的值可以改变,但是不能更改其所指对象的值。
##迭代器的算术操作:
iter+n
iter-n
可以对迭代器加上或减去一个整型值,这样做的结果是*产生一个新的迭代器*,其位置在iter所指元素的前或后n个元素的位置。
iter1-iter2
对两个迭代器进行加减运算,当然前提是两者必须指向同一个vector容器,这个表达式的结果是一个different_type类型,同string::size_type类型不同的是,两者虽然都是类类型,但是后者是近似于unsigned类型,前者是一个signed类型,因为距离运算可能产生负值。
可以使用迭代器的算术操作来移动迭代器可直接指向某个元素:
vector<string>::iterator mid=v1.begin()+v1.size()/2;
bitset 类型:
对于一些要处理二进制位的有序集,每个位可能包含0(关)值或1(开)值。位是用来保存一组项或条件的yes/no信息的简洁方法。bitset类简化了位集的处理,要使用bitset类就必须包含相关的头文件
#include<bitset>
using std::biest;
bitset对象的初始化:
bitset<32> bitvec;
当然还有很多种初始化式,在这里就不一一列举了。
有一点需要注意,就是在括号中,给出的长度之必须是常量表达式,
##
使用unsigned long 值作为bitset对象的初始值时,该值将会转化成二进制模式。而bitset对象中位集作为这种位模式的副本。如果bitset类型长度小于unsigned long值得二进制位数,则只使用unsigned值中的低阶位,超过bitset的高阶位将被丢弃。
例如:
在32的unsigned long的机器上,十六进制0xffff表示为二进制是16个1和16个0
bitset<16> bitvec1(0xffff); //bits 0...15 are set to 1
bitset<32> bitvec2(oxffff); // bits 0...15 ate set to 1;16...32 are 0;
bitset<128> bitvec3(0xfff); //bits 32....127 initialized to zero
##
使用string对象初始化bitset对象:
使用string对象初始化bitset对象时,string对象直接表示为位模式,
**从string对象读入位集的顺序是从右往左**。
string str("1100");
bitset<32> bitvec4(str);
bitvec4的位模式中2.3位都是1,其余则是 0,。首先用string的高阶位来初始化bitset中的低阶位,它们之间的是反向转化的。