`

《C++ Primer中文版》(第四版)信息汇总(三)

 
阅读更多

本部分主要是讨论“容器和算法”,具体内容包括:顺序容器、关联容器以及泛型算法。第9章深入探讨vector和其他顺序容器类型,第10章介绍关联容器,即不是顺序排列,而是按键排序的,第11章介绍泛型算法,这些算法通常作用于容器或序列中某一范围的元素。所谓泛型指的就是这些算法可以作用于不同的容器类型,而这些容器又可以容纳多种不同类型的元素。

九、顺序容器
将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素,这就是顺序容器,顺序容器的元素排列次序与元素值无关,而是由元素添加到容器里的次序决定,标准库定义了三种顺序容器类型:vector、list和deque(双端队列),他们的差别在于访问元素的方式,以及添加或删除元素相关操作的运行代价,标准库还提供了三种容器适配器:stack、queue、priority_queue,适配器是根据原始的容器类型所提供的操作,通过定义新的操作接口,来适应基础的容器类型。

1、顺序容器类型:容器只定义了少量的操作,大多数额外操作则由算法库提供。

vector:支持快速随机访问;list:支持快速插入/删除;deque:双端队列

2、顺序容器的定义:所有的容器类型都定义了默认构造函数,用于创建指定类型的空容器对象。默认构造函数不带参数。

view plaincopy to clipboardprint?
#include<vector>
#include<list>
#include<deque>

vector<string> svec;
list<int> ilist;
deque<Sales_item> items;
#include<vector>
#include<list>
#include<deque>

vector<string> svec;
list<int> ilist;
deque<Sales_item> items;

3、将一个容器复制给另一个容器时,类型必须匹配,容器类型和元素类型都必须相同。

view plaincopy to clipboardprint?
vector<int> ivec;
vector<int> ivec2(ivec); //ok,ivec is vector<int>
list<int> ilist(ivec); //error,ivec is not list<int>
vector<double> dvec(ivec); //error,ivec holds int not double
vector<int> ivec;
vector<int> ivec2(ivec); //ok,ivec is vector<int>
list<int> ilist(ivec); //error,ivec is not list<int>
vector<double> dvec(ivec); //error,ivec holds int not double

4、初始化为一段元素的副本:尽管不能直接将一种容器内的元素复制给另一个容器,但系统允许通过传递一对迭代器间接实现该功能。使用迭代器时,不要求容器类型相同,容器内的元素类型也可以不相同,只要它们相互兼容,能够将要复制的元素转化为所构建的新容器的元素类型,即可实现复制。

view plaincopy to clipboardprint?
list<string> slist(svec.begin(),svec.end());
vector<string>::iterator mid=svec.begin()+svec.size()/2;
deque<string> front(svec.begin(),mid);
deque<string> back(mid,svec.end());
list<string> slist(svec.begin(),svec.end());
vector<string>::iterator mid=svec.begin()+svec.size()/2;
deque<string> front(svec.begin(),mid);
deque<string> back(mid,svec.end());

5、创建顺序容器时,可显式指定容器大小和一个元素初始化式,接受容器大小做形参的构造函数只适用于顺序容器,而关联容器不支持这种初始化。

view plaincopy to clipboardprint?
const list<int>::size_type list_size=64;
list<string> slist(list_size,"eh?");
const list<int>::size_type list_size=64;
list<string> slist(list_size,"eh?");

6、容器的容器,注意在指定容器元素为容器类型时,必须使用空格。否则系统会认为>>是单个符号,为右移操作符。

view plaincopy to clipboardprint?
vector< vector<string> > lines;//ok,space required between close>

vector< vector<string>> lines;//error,>>treated as shift operator
vector< vector<string> > lines;//ok,space required between close>

vector< vector<string>> lines;//error,>>treated as shift operator

7、常用迭代器运算

view plaincopy to clipboardprint?
*iter;//返回迭代器iter所指向的元素的引用
iter->mem;//对iter进行解引用,获取指定元素中名为mem的成员。等效于(*iter).mem
iter1==iter2;//比较两个迭代器是否相等,当两个迭代器指向同一个容器
iter1!=iter2;//中的同一个元素,或者都指向end(),两个迭代器相等
*iter;//返回迭代器iter所指向的元素的引用
iter->mem;//对iter进行解引用,获取指定元素中名为mem的成员。等效于(*iter).mem
iter1==iter2;//比较两个迭代器是否相等,当两个迭代器指向同一个容器
iter1!=iter2;//中的同一个元素,或者都指向end(),两个迭代器相等


8、vector和deque容器的迭代器提供额外的运算:迭代器算术运算,以及使用除了==和!=之外的关系操作符来比较两个迭代器。

view plaincopy to clipboardprint?
iter+n;
iter-n;
iter1+=iter2;
iter1-=iter2;//这是迭代器加减法的复合赋值运算,将iter1加上或减去iter2的运算结果赋给iter1
iter1-iter2;//两个迭代器的减法,其运算结果加上右边的迭代器即得左边的迭代器
iter+n;
iter-n;
iter1+=iter2;
iter1-=iter2;//这是迭代器加减法的复合赋值运算,将iter1加上或减去iter2的运算结果赋给iter1
iter1-iter2;//两个迭代器的减法,其运算结果加上右边的迭代器即得左边的迭代器

9、使用左闭合区间[first,last)的编程意义:当first与last相等时,迭代器范围为空;当first与last不相等时,迭代器范围内至少有一个元素,而且first指向该区间中的第一个元素。此外,通过若干次自增运算可以使first的值不断增大,直到first==last为止。

10、begin和end成员

c.begin():返回一个迭代器,它指向容器c的第一个元素;c.end():返回一个迭代器,它指向容器c的最后一个元素的下一位置

c.rbegin():返回一个逆序迭代器,它指向容器c的最后一个元素;c.rend():返回一个逆序迭代器,它指向容器c的第一个元素前面的位置

11、在顺序容器中添加元素:

view plaincopy to clipboardprint?
c.push_back(t);//在容器c的尾部添加值为t的元素,返回void类型
c.push_front(t);//在容器c的前端添加值为t的元素,返回void类型,只适用list和deque容器类型
c.insert(p,t);//在迭代器p所指向的元素前面插入值为t的新元素,返回指向新添加元素的迭代器
c.insert(p,n,t);//在迭代器p所指向的元素前面插入n个值为t的新元素,返回void类型
c.insert(p,b,e);//在迭代器p所指向的元素前面插入由迭代器b和e标记的范围内的元素,返回void类型
c.push_back(t);//在容器c的尾部添加值为t的元素,返回void类型
c.push_front(t);//在容器c的前端添加值为t的元素,返回void类型,只适用list和deque容器类型
c.insert(p,t);//在迭代器p所指向的元素前面插入值为t的新元素,返回指向新添加元素的迭代器
c.insert(p,n,t);//在迭代器p所指向的元素前面插入n个值为t的新元素,返回void类型
c.insert(p,b,e);//在迭代器p所指向的元素前面插入由迭代器b和e标记的范围内的元素,返回void类型

12、避免存储end操作返回的迭代器,如下面代码,该段代码将导致死循环,问题在于这个程序将end操作返回的迭代器值存储在名为last的局部变量中,循环体中实现了元素的添加运算,添加元素会使得存储在last中的迭代器失效。

view plaincopy to clipboardprint?
vector<int>::iterator first=v.begin(),last=v.end();

while(first!=last){
first=v.insert(first,32);
++first;
}
vector<int>::iterator first=v.begin(),last=v.end();

while(first!=last){
first=v.insert(first,32);
++first;
}

为了避免存储end迭代器,可以在每次做完插入运算后重新计算end迭代器值:

view plaincopy to clipboardprint?
while(first!=v.end()){
first=v.insert(first.42);
++first;
}
while(first!=v.end()){
first=v.insert(first.42);
++first;
}

13、所有的容器类型都支持用关系操作符来实现两个容器的比较,比较的容器必须具有相同的容器类型,而且其元素类型也必须相同。

view plaincopy to clipboardprint?
/*
ivec1:1 3 5 7 9 12
ivec2:0 2 4 6 8 10 12
ivec3:1 3 9
ivec4:1 3 5 7
ivec5:1 3 5 7 9 12
*/
ivec1<ivec2;//false
ivec2<ivec1;//true
ivec1<ivec3;//true
ivec1<ivec4;//false
ivec1==ivec4;//false
ivec1==ivec5;//true
/*
ivec1:1 3 5 7 9 12
ivec2:0 2 4 6 8 10 12
ivec3:1 3 9
ivec4:1 3 5 7
ivec5:1 3 5 7 9 12
*/
ivec1<ivec2;//false
ivec2<ivec1;//true
ivec1<ivec3;//true
ivec1<ivec4;//false
ivec1==ivec4;//false
ivec1==ivec5;//true

14、容器大小的操作

view plaincopy to clipboardprint?
c.size();//返回容器c中的元素个数。返回类型为c::size_type
c.max_size();//返回容器c可容纳的最多元素个数,返回类型为c::size_type
c.empty();//返回标记容器大小是否为0的布尔值
e.resize(n);//调整容器c的长度大小,使其容纳n个元素,如果n<c.size(),则删除多出来的元素,否则添加
//采用值初始化的新元素
e.resize(n,t);//调整c的大小,使其能容纳n个元素,所有添加的元素值都为t
c.size();//返回容器c中的元素个数。返回类型为c::size_type
c.max_size();//返回容器c可容纳的最多元素个数,返回类型为c::size_type
c.empty();//返回标记容器大小是否为0的布尔值
e.resize(n);//调整容器c的长度大小,使其容纳n个元素,如果n<c.size(),则删除多出来的元素,否则添加
//采用值初始化的新元素
e.resize(n,t);//调整c的大小,使其能容纳n个元素,所有添加的元素值都为t

15、访问元素:

view plaincopy to clipboardprint?
c.back();//返回容器c的最后一个元素的引用。如果c为空,则该操作未定义
c.front();//返回容器c的第一元素的引用。
c[n];//返回下标为n的元素的引用,该操作只适用于vector和deque
c.at(n);//返回下标为n的元素的引用,如果下标越界,则该操作未定义,该操作只适用于vector和deque
c.back();//返回容器c的最后一个元素的引用。如果c为空,则该操作未定义
c.front();//返回容器c的第一元素的引用。
c[n];//返回下标为n的元素的引用,该操作只适用于vector和deque
c.at(n);//返回下标为n的元素的引用,如果下标越界,则该操作未定义,该操作只适用于vector和deque

16、删除元素

view plaincopy to clipboardprint?
c.erase(p);//删除迭代器p所指向的元素,返回一个迭代器,它指向被删除元素后面的元素
e.erase(b,e);//删除迭代器b和e所标记的范围内的元素
c.clear();//删除容器c内的所有元素,返回void
c.pop_back();//删除容器c的最后一个元素,返回void
c.pop_front();//删除容器c的第一个元素,返回void,只适用于list或deque容器
c.erase(p);//删除迭代器p所指向的元素,返回一个迭代器,它指向被删除元素后面的元素
e.erase(b,e);//删除迭代器b和e所标记的范围内的元素
c.clear();//删除容器c内的所有元素,返回void
c.pop_back();//删除容器c的最后一个元素,返回void
c.pop_front();//删除容器c的第一个元素,返回void,只适用于list或deque容器

17、赋值与swap

view plaincopy to clipboardprint?
c1=c2;//删除容器c1的所有元素,然后将c2的值复制给c1
c1.swap(c2);//交换内容
c.assign(b,e);//重新设置c的元素,b和e必须不是指向c中元素的迭代器
c.assign(n,t);//将容器c重新设置为存储n个值为t的元素
c1=c2;//删除容器c1的所有元素,然后将c2的值复制给c1
c1.swap(c2);//交换内容
c.assign(b,e);//重新设置c的元素,b和e必须不是指向c中元素的迭代器
c.assign(n,t);//将容器c重新设置为存储n个值为t的元素

18、容器的capacity(容量)和size(长度)的区别:size指容器当前拥有的元素个数;而capacity则指容器在必须分配心存储空间之前可以存储的元素个数。

19、string类型的查找操作,这些操作都返回string::size_type类型的值

view plaincopy to clipboardprint?
s.find(args);//在s中查找args的第一次出现
s.rfine(args);//在s中查找args的最后一次出现
s.find_first_of(args);//在s中查找args的任意字符的第一次出现
s.find_last_of(args);//在s中查找args的任意字符的最后一次出现
s.find_first_not_of(args);//在s中查找第一个不属于args的字符
s.find_last_not_of(args);//在s中查找最后一个不属于args的字符
s.find(args);//在s中查找args的第一次出现
s.rfine(args);//在s中查找args的最后一次出现
s.find_first_of(args);//在s中查找args的任意字符的第一次出现
s.find_last_of(args);//在s中查找args的任意字符的最后一次出现
s.find_first_not_of(args);//在s中查找第一个不属于args的字符
s.find_last_not_of(args);//在s中查找最后一个不属于args的字符

20、容器适配器:包括容器适配器、迭代器适配器和函数适配器。使用适配器是,必须包含相关的头文件:

view plaincopy to clipboardprint?
#include<stack>
#include<queue>
#include<stack>
#include<queue>

十、关联容器
关联容器和顺序容器的本质区别在于:关联容器通过键存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素,虽然关联容器的大部分行为与顺序容器相同,但其独特之处在于支持键的使用。关联容器支持通过键来高效地查找和读取元素,两个基本的关联容器类型是map和set,map的元素以键-值(key-value)对的形式组织,键用作元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。

1、关联容器类型包括:(1) map,关联数组,元素通过键来存储和读取;(2) set,大小可变的集合,支持通过键实现的快速读取;(3) multimap,支持同一个键多次出现的map类型;(4) multiset,支持同一个键多次出现的set类型

2、一般来说,如果希望有效地存储不同值的集合,那么使用set容器比较合适,而map容器则更适用于存储每个键所关联的值的情况。

3、pair类型,该类型在utility头文件中定义

view plaincopy to clipboardprint?
#include<utility>

pair<T1,T2> p1;//创建一个空的pair对象,它们的两个元素分别是T1和T2类型,采用值初始化

pair<T1,T2> p1(v1,v2);//创建一个pair对象,它们的两个元素分别是T1和T2类型,其中first成员初始化为v1,
//而second初始化为v2

make_pair(v1,v2);//以v1和v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型

p.first;//返回p中名为first的数据成员

p.second;//返回p中名为second的数据成员
#include<utility>

pair<T1,T2> p1;//创建一个空的pair对象,它们的两个元素分别是T1和T2类型,采用值初始化

pair<T1,T2> p1(v1,v2);//创建一个pair对象,它们的两个元素分别是T1和T2类型,其中first成员初始化为v1,
//而second初始化为v2

make_pair(v1,v2);//以v1和v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型

p.first;//返回p中名为first的数据成员

p.second;//返回p中名为second的数据成员

举例说明如下:

view plaincopy to clipboardprint?
pair<string,string> anno;
pair<string,int>word_count;

typedef pair<string,string> Author;
Author proust("Xue","Jamy");

//pair对象的操作
pair<string,string> author("James","Joye");
string firstBook;
if(author.first="Xue" && author.second=="Jamy")
firstBook="The Love Story";

//生成新的pair对象
pair<string,string> next_auth;
string first,last;
while(cin>>first>>last){
next_auth=make_pair(first,second);
}
pair<string,string> anno;
pair<string,int>word_count;

typedef pair<string,string> Author;
Author proust("Xue","Jamy");

//pair对象的操作
pair<string,string> author("James","Joye");
string firstBook;
if(author.first="Xue" && author.second=="Jamy")
firstBook="The Love Story";

//生成新的pair对象
pair<string,string> next_auth;
string first,last;
while(cin>>first>>last){
next_auth=make_pair(first,second);
}


4、关联容器共享大部分但并非全部的顺序容器操作,关联容器不提供front,push_front,pop_front,back,push_back以及pop_back操作。关联容器不能通过容器大小来定义,因为这样的话就无法知道键所对应的值是什么,关联容器还可以根据键来排列元素。

5、map类型的定义:必须具备map头文件

view plaincopy to clipboardprint?
map<string,int> word_count;

map<k,v> m;//创建一个名为m的空map对象,其键和值的类型分别为k和v
map<k,v> m(m2);//创建m2的副本m,m和m2必须有相同的键类型和值类型
map<k,v> m(b,e);//创建map类型的对象m,存储迭代器b和c标记的范围内所有的元素的副本,元素的类型必须
//能够转换为pair<const k,v>
map<string,int> word_count;

map<k,v> m;//创建一个名为m的空map对象,其键和值的类型分别为k和v
map<k,v> m(m2);//创建m2的副本m,m和m2必须有相同的键类型和值类型
map<k,v> m(b,e);//创建map类型的对象m,存储迭代器b和c标记的范围内所有的元素的副本,元素的类型必须
//能够转换为pair<const k,v>

6、实际应用中,键类型必须定义<操作符,而且该操作符应能正确的工作。至于是否支持其他的关系或相当运算,则不做要求。

7、map定义的类型

view plaincopy to clipboardprint?
map<K,V>::key_type //在map容器中,用作索引的键的类型
map<K,V>::mapped_type //在map容器中,键所关联的值的类型
map<K,V>::value_type //一个pair类型,它的first元素具有const map<K,V>::key_type类型,
//而second元素则为map<K,V>::mapped_type类型

//map迭代器进行解引用将产生pair类型的对象
map<string,int>::iterator map_it=word_count.begin();
cout<<map_it->first;
cout<<" "<<map_it->second;
map_it->first="new key"; //Error:key is const
++map_it->second; //OK:we can change value through an iterator
map<K,V>::key_type //在map容器中,用作索引的键的类型
map<K,V>::mapped_type //在map容器中,键所关联的值的类型
map<K,V>::value_type //一个pair类型,它的first元素具有const map<K,V>::key_type类型,
//而second元素则为map<K,V>::mapped_type类型

//map迭代器进行解引用将产生pair类型的对象
map<string,int>::iterator map_it=word_count.begin();
cout<<map_it->first;
cout<<" "<<map_it->second;
map_it->first="new key"; //Error:key is const
++map_it->second; //OK:we can change value through an iterator

8、给map添加元素:可以用insert成员实现,或者先用下标操作符获取元素,然后给获取的元素赋值。使用下标访问map与使用下标访问数组或vector的行为截然不同,用下标访问不存在的元素将导致在map容器中添加一个新的元素,它的键即为该下标值。

view plaincopy to clipboardprint?
map<string,int> word_count;
word_count["Anna"]=1;//如果word_count中没有Anna的元素,则插入

m.insert(e);//e是一个用在m上的value_type类型的值。
m.insert(beg,end);//beg和end是标记元素范围的迭代器
m.insert(iter,e);//e是一个用在m上的value_type类型的值。

word_count.insert(map<string,int>::value_type("Anna",1));
word_count.insert(make_pair("Anna",1));
map<string,int> word_count;
word_count["Anna"]=1;//如果word_count中没有Anna的元素,则插入

m.insert(e);//e是一个用在m上的value_type类型的值。
m.insert(beg,end);//beg和end是标记元素范围的迭代器
m.insert(iter,e);//e是一个用在m上的value_type类型的值。

word_count.insert(map<string,int>::value_type("Anna",1));
word_count.insert(make_pair("Anna",1));

9、查找并读取map中的元素

view plaincopy to clipboardprint?
m.count(k);//返回m中k的出现次数
m.find(k);//如果m容器中存在按k索引的元素,则返回指向该元素的迭代器,如果不存在,则返回end()
m.count(k);//返回m中k的出现次数
m.find(k);//如果m容器中存在按k索引的元素,则返回指向该元素的迭代器,如果不存在,则返回end()

10、从map对象中删除元素

view plaincopy to clipboardprint?
m.erase(k);//删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数

m.erase(p);//从m中删除迭代器p所指向的元素。p必须指向m中确实存在的元素,而且不能等于m.end(),返回void

m.erase(b,e);//从m中删除一段范围内的元素,返回void
m.erase(k);//删除m中键为k的元素。返回size_type类型的值,表示删除的元素个数

m.erase(p);//从m中删除迭代器p所指向的元素。p必须指向m中确实存在的元素,而且不能等于m.end(),返回void

m.erase(b,e);//从m中删除一段范围内的元素,返回void

11、set类型:只是单纯的键的集合。

set容器支持大部分的map操作,两种例外包括:set不支持下标操作符,而且没有定义mapped_type类型,在set容器中,value_type不是pair类型,而是与key_type相同的类型,它们指的是set中存储的元素类型。

12、set容器的定义和使用:必须包含set头文件

与map容器一样,set容器的每个键都只能对应一个元素,以一段范围的元素初始化set对象,或在set对象中插入一组元素时,对于每个键,事实上都只添加一个元素。

view plaincopy to clipboardprint?
vector<int> ivec;
for(vector<int>::size_type i=0;i!=10;++i){
ivec.push_back(i);
ivec.push_back(i);
}//ivec有20个元素,即两个0~9的副本

set<int> iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl; //20
cout<<iset.size()<<endkl//10:iset只能保存不同元素的值
vector<int> ivec;
for(vector<int>::size_type i=0;i!=10;++i){
ivec.push_back(i);
ivec.push_back(i);
}//ivec有20个元素,即两个0~9的副本

set<int> iset(ivec.begin(),ivec.end());
cout<<ivec.size()<<endl; //20
cout<<iset.size()<<endkl//10:iset只能保存不同元素的值

13、multimap和multiset类型:允许一个键对应多个实例。multimap和multiset所支持的操作分别与map和set的操作相同,只有一个例外:multimap不支持下标运算。因为这类容器中,某个键可能对应多个值。

(1) 元素的添加和删除

view plaincopy to clipboardprint?
multimap<string,string> authors;

//Add Elements
authors.insert(make_pair(string("Xue"),string("Love")));
authors.insert(make_pair(string("Xue"),string("Hello")));

//Del
string search_item("Xue");
multimap<string,string>::size_type cnt=authors.erase(search_item);
multimap<string,string> authors;

//Add Elements
authors.insert(make_pair(string("Xue"),string("Love")));
authors.insert(make_pair(string("Xue"),string("Hello")));

//Del
string search_item("Xue");
multimap<string,string>::size_type cnt=authors.erase(search_item);

(2) 与众不同的面向迭代器的解决方案

view plaincopy to clipboardprint?
m.lower_bound(k);//返回一个迭代器,指向键小于k的第一个元素
m.upper_bound(k);//返回一个迭代器,指向键大于k的第一个元素
m.equal_bound(k);//返回一个迭代器的pair对象,它的first成员等价于m.lower_bound(k).
//而second成员等价于m.upper_bound(k)
m.lower_bound(k);//返回一个迭代器,指向键小于k的第一个元素
m.upper_bound(k);//返回一个迭代器,指向键大于k的第一个元素
m.equal_bound(k);//返回一个迭代器的pair对象,它的first成员等价于m.lower_bound(k).
//而second成员等价于m.upper_bound(k)

(3) equal_range函数:返回存储一对迭代器的pair对象,如果该值存在,则pair对象中的第一个迭代器指向该键关联的第一个实例,第二个迭代器指向该键关联的最后一个实例的下一个位置,如果找不到匹配的元素,则pair对象中的两个迭代器都将指向此键应该插入的位置。

十一、泛型算法
标准库容器定义的操作非常少,标准库没有给容器添加大量的功能函数,而是选择提供一组算法,这些算法大都不依赖特定的容器类型,可作用在不同类型的容器和不同类型的元素中,本章详细介绍泛型算法以及对迭代器更详尽的描述。泛型算法本来从来不执行容器操作,只是单独依赖迭代器和迭代器操作实现,算法基于迭代器及其操作实现,而并非基于容器操作。

1、使用泛型算法必须包含algorithm头文件#include<algorithm>.标准库还定义了一组泛化的算术算法,其命名习惯与泛型算法相同,使用这些算法则必须包含numberic头文件#include<numeric>。

2、用于指定累加起始值的第三个实参是必要的,因为accumulate对将要累加的元素类型一无所知。

view plaincopy to clipboardprint?
//将sum设置为vec的元素之和再加上42
int sum=accumulate(vec.begin(),vec.end(),42);

//把string型的vector容器的元素连接起来
string sum=accumulate(v.begin(),v.end(),string(""))'
//将sum设置为vec的元素之和再加上42
int sum=accumulate(vec.begin(),vec.end(),42);

//把string型的vector容器的元素连接起来
string sum=accumulate(v.begin(),v.end(),string(""))'

3、find_first_of的使用:在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素,如果找不到匹配元素,则返回第一个范围的end迭代器。以下例子统计有多少个名字同时出现在这两个列表中。

view plaincopy to clipboardprint?
size_t cnt=0;
list<string>::iterator it=roster1.begin();
while((it=find_first_of(it,roster1.end(),roster2.begin(),roster2.end())){
++cnt;
++it;
}
cout<<"Found"<<cnt
<<"name on both rosters"<<endl;
size_t cnt=0;
list<string>::iterator it=roster1.begin();
while((it=find_first_of(it,roster1.end(),roster2.begin(),roster2.end())){
++cnt;
++it;
}
cout<<"Found"<<cnt
<<"name on both rosters"<<endl;

4、写容器元素的算法,有些算法直接将数据写入到输入序列,另外一些则带有一个额外的迭代器参数指定写入目标。

(1) 写入输入序列的元素:本质上是安全的,只会写入与制定输入范围数量相同的元素。

view plaincopy to clipboardprint?
fill(vec.begin(),vec.end(),0);
fill(vec.begin(),vec.end(),0);

(2) 不检查写入操作的算法:fill_n函数带有的参数包括一个迭代器、一个计数器以及一个值。注意不能对没有元素的空容器调用

fill_n函数(或者类似的算法)

view plaincopy to clipboardprint?
vector<int> vec;//empty vector
fill_n(vec.begin(),10,0);//Error:attempts to write 10 elements in vec
vector<int> vec;//empty vector
fill_n(vec.begin(),10,0);//Error:attempts to write 10 elements in vec

(3) 确保算法有足够的元素存储输入数据的一种方法是使用插入迭代器,插入迭代器可以给基础容器添加元素的迭代器,通常用迭代器给容器元素赋值时,被赋值的是迭代器所指向的元素,而是用插入迭代器赋值时,则会在容器中添加一个新元素,其值等于赋值运算的右操作数的值。为了说明如何安全使用写容器的算法,下面使用back_inserter,必须包含iterator头文件。

view plaincopy to clipboardprint?
//引入back_inserter
vector<int> vec;
fill_n(back_inserter(vec),10,0);

//写入到目标迭代器的算法:copy从输入范围读取元素,然后赋值给ivec
vector<int> ivec;
copy(ilist.begin(),ilist.end(),back_inserter(ivec));

//上述例子的效率比较差,用下面方法代替
vector<int> ivec(ilist.begin(),ilist.end());

//这个调用将所有值为0的实例替换成42
replace(ilist.begin(),ilist.end,0,42);

//ilist没有改变,ivec存储ilist的一份副本,在ivec中所有0都变成了42
vector<int> ivec;
replace_copy(ilist.begin(),ilist.end(),back_inserter(ivec),0,42);
//引入back_inserter
vector<int> vec;
fill_n(back_inserter(vec),10,0);

//写入到目标迭代器的算法:copy从输入范围读取元素,然后赋值给ivec
vector<int> ivec;
copy(ilist.begin(),ilist.end(),back_inserter(ivec));

//上述例子的效率比较差,用下面方法代替
vector<int> ivec(ilist.begin(),ilist.end());

//这个调用将所有值为0的实例替换成42
replace(ilist.begin(),ilist.end,0,42);

//ilist没有改变,ivec存储ilist的一份副本,在ivec中所有0都变成了42
vector<int> ivec;
replace_copy(ilist.begin(),ilist.end(),back_inserter(ivec),0,42);

5、对容器元素重新排序的算法,一个实例:统计段落中使用了多少个由6个或以上的字母组成的单词。

(1) 去除重复:

view plaincopy to clipboardprint?
sort(words.begin(),words.end());
vector<string>::iterator end_unique=unique(words.begin(),words.end());
words.erase(end_unique,words.end());
sort(words.begin(),words.end());
vector<string>::iterator end_unique=unique(words.begin(),words.end());
words.erase(end_unique,words.end());

(2) 定义需要的使用函数:

view plaincopy to clipboardprint?
bool isShorter(const string &s1,const string &s2)
{
return s1.size()<s2.size();
}

bool GT6(const string &s)
{
return s.size()>=6;
}
bool isShorter(const string &s1,const string &s2)
{
return s1.size()<s2.size();
}

bool GT6(const string &s)
{
return s.size()>=6;
}

(3) 排序算法,stable_sort算法保留相等元素的原始相对位置。

view plaincopy to clipboardprint?
stable_sort(words.begin(),words.end(),isShorter);
stable_sort(words.begin(),words.end(),isShorter);

(4) 统计长度不小于6的单词

view plaincopy to clipboardprint?
vector<string>::size_type wc=count_if(words.begin(),words.end(),GT6);

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/rocket5725/archive/2009/09/19/4568924.aspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics