Standard Template Library(STL)主要由两种组件构成:一是容器(container),包括vector、list、set、map等类,另一种组件时用以操作这些容器的所谓泛型算法(generic algorithm),包括find(),sort(),replace(),merge()等。
容器分为顺序性容器(sequential container)—— 按照顺序依次进行操作,多用到迭代(iterate)和关联性容器(associative container)—— 可快速查找容器中的元素值。
map类型为一对对的 key/value 组合,key用于查找,value用来表示要存储或取出的数据。set类型仅含key,用于判断某值是否存在其中。
泛型算法:与操作的元素类型无关的算法,主要通过 function template 技术,达到与操作对象类型相互独立的目的,其诀窍是通过一对iterator(first和last),标示着要进行迭代的元素范围。
可处理任何定义了equality(相等)运算分类型的find函数
template <typename elemType>
elemType* find(const vector<elemType> &vec, const elemType &value)
{
for(int ix=0;ix<vec.size();ix++)
if(vec[ix] == value)
return &vec[ix];
return 0;
}
数组传递给函数,或是由函数返回,仅有第一个元素的地址被传递。
举例:int min(int *array){...}
。min 函数可接受任意大小的数组,但不知道array大小,针对此问题,可有以下两种解决办法
template <typename elemType> elemType* find(const elemType *array,int size,const elemType &value);
template <typename elemType> elemType* find(const elemType *array, const elemType *sentinel,const elemType &value);
vector<string> svec; //存储string地vector
if(!svec.empty()) //当不是空的就可以调用find函数了
list元素以一组指针相互链接(linked):前向(forward)指针指向下一个(next)元素,后向(backword)指针指向上一个(preceding)元素。
由于list地所有元素宾补储存在连续的内存空间里,所以底层指针的工作方式和vector、array不同,但通过进一步扩展和抽象,可以使得find()函数也支持list,即Iterator
设计一组iterator class,使得可以使用“和指针相同的语法”进行程序编写,需要设计iterator class的deference(提领,*)、inequity(不等,!=)、increment(递增,++),由类内的inline函数提供。其实现效果为:对list iterator而言,其递增函数会沿着list的指针前进到下一个元素,对vector iterator,递增函数是增加地址值来前进到下一个元素。
vector<string> svec;
//iter 指向一个vector,vector元素类型为string
//iter初始值为第一个元素
vector<string>::iterator iter = svec.begin();
PS:双冒号(::)表示iterator是string vector定义内的嵌套类型。
对于const vector,使用const_iterator 进行遍历操作,const_iterator只允许读取vector的元素,但不允许任何写入操作
const vector<string> cs_vec;
vector<string>::const_iterator iter = cs_vec.begin();
cout<<*iter<<endl; //使用一般指针提领方式接可以取得iterator所指的元素值
cout<<iter->size()<<endl //使用arrow运算符可以调用底部string元素所提供的操作
对find函数重新实现,使得同时支持两种形式:一对指针或是一对指向某容器的iterator
template <typename IteratorType, typename elemType>
IteratorType find(IteratorType first, IteratorType last, const elemType &value)
{
for(;first !=last;++first)
if(*first == value)
return first;
return last;
}
int main()
{
const int asize =8;
int ia[asize]={1,1,2,3,5,8,13,21};
//以ia的8个元素作为list和vector的初值
vector<int> ivec(ia,ia+asize);
list<int> ilist(ia,ia+asize);
int *pia = find(ia,ia+asize,1024);
if(ia!=ia+asize) //找到了
vector<int>::iterator it;
it=find(ivec.begin(),ivec.end(),,1024);
if(it!=ivec.end())
list<int>::iterator iter;
iter=find(ilist.begin(),ilist.end(),,1024);
if(iter!=ilist.end())
}
重新实现的find()函数使用了底部元素所属类型的equality(相等)运算符,如果底部元素未定义该运算符,则会出错,解决办法:
容器类的(以及string类)的共通操作:
三种顺序性容器:vector、list、deque
list是以双向链接来存储内容,每个元素包含value,back指针(指向前一个),front指针(指向下一个),在list任意位置插入
deque是
使用顺序性容器方法
包含相应的头文件
#include <vector>
#include <list>
#include <deque>
//产生顺序性容器的方法
list<string> slist; // 产生空的容器
vector<int> ivec(32); //产生特定大小容器,每个元素以其默认值为初值
list<string> slist(16,"unassigned");
int ia[8]={1,1,2,3,5,8,13,21};
vector<int> fib(ia,ia+8); //通过一对iterator产生容器,iterator标示初值元素的范围
list<string> slist; //空容器
//填充slist
list<string> slist2(slist); //根据某个容器产生新容器,复制容器内的元素,作为新容器初值
PS:push_back()和pop_back()允许在容器末尾进行插入和删除操作。除此之外,list和deque(不包括vector)还提供了push_front()和pop_front(),pop_back()、pop_front()不会返回被删除的元素值,如果要读取最前端/后端元素,使用front()/back()
其他变形操作:
使用泛型算法,首先需要包含头文件
#include <algorithm>
常用的算法可参考附录B
function object: 某种class实例对象,这类class对function call运算符做了重载操作,于是可以使function object当作一般函数使用。
标准库有定义一部分function object,分为算术运算,关系运算和逻辑运算三大类,使用需要包含头文件
#include <functional>
function object adapter:为了调整function object使得更好地应用于函数,包含:
binder adapter(绑定适配器):将function object地参数绑定至特定值,使得二元运算符变为一元运算符,标准库提供了bind1st(function object, value)、bind2nd(function object, value)
negator:对function object的真伪值取反,not1可对一元的function object取反,not2可对二元的取反。
map是key/value对,字典是map的一种实例。使用map,需包含头文件
#include <map>
#include <string>
map<string,int> words; //定义一个map对象
words["vermeer"]=1; //输入一个key/value对
//字数统计工作
string tword;
while(cin>>tword)
words[tword]++: //会取出相应的value,如果没有就创建,获得默认值0,再加一
map<string,int>::iterator it=words.begin();
for(;it!=words.end();++it)
cout<<"key:"<<it->first //map对象有两个特殊的member:first和second,分别对应key和value
<<"value:"<<it->second <<endl;
**查询map中是否存在某个key:
//查找为words.find("vermeer")
int count=0;
map<string,int>::iterator it;
it=words.find("vermeer");
if(it!=words.end())
count=it->second;
key在其中,则返回指向key/value对的iterator,否则返回end();
Set由一群key组合而成,查询某值是否在集合内,用set
#include <set>
#include <string>
set<string> word_exclusion; //定义一个排除字眼的set
对任何key值,set只存储一份(存储多份相同的key值,需要multiset),set元素根据所属类型默认的从小到大顺序排列。
为了解决目的端容器大小不确定的问题,标准库提供了三个 insert adaption,来避免使用容器的assignment运算符
vector<int> result_vec;
unique_copy(ivec.begin(),ivec.end(),back_inserter(result_vec));
标准库定义有供输入输出使用的iostream iterator类,成为istream_iterator、ostream_iterator,分别支持单一类型的元素的读取和写入,需包含头文件
#include <iterator>
利用istream_iterator从标准输入设备读取字符串,需要设定一对iterator:
istream_iterator<string> is(cin); //将is绑顶至标准输入设备,作为first iterator
istream_iterator<string> eof; //在定义istream_iterator时不为其指定对象,便代表了end-of-file
ostream_iterator 标示字符串元素到标准输出
ostream_iterator<string> os(cout," ")
第二个参数可以是C-style字符串,也可以是字符串常量,表示输出时各个元素的分隔符。
当希望从文件中读取和写入时,将istream_iterator绑定到ifstream对象,将ostream_iterator绑定到ofstream对象
ifstream in_file("input_file.txt");
ofstream out_file("output_file.txt");
istream_iterator<string> is(in_file);
ostream_iterator<string> os(out_file," ");
原文:https://www.cnblogs.com/senyablog/p/14401372.html