标准容器定义的操作通常包含添加和删除元素;访问第一个和最后一个元素;获取容器大小,并在某些情况下重设容器大小;获取指向第一个和最后一个容器的下一位置的迭代器。
用户通常希望对容器元素有更多有用操作,比如排序、查找等。标准库没有为每种容器定义相关成员函数,而是定义了一组泛型算法。
int value=41;
vector<int>::const_iterator result =
find(vec.begin(),vec.end(),search_value);
cout<<"The value"<<value
<<(result==vec.end()
?"is not present" //找不到就返回最后一个元素下一个位置迭代器
:"is present") //找到就返回元素位置迭代器
<<endl
find函数使用两个迭代器和一个值,检查两个迭代器之间所有元素,找到和值相等的元素就会返回该元素迭代器,找不到就会返回第二个迭代器实参,只要比较返回值是否等于第二个迭代器实参就知道有没有找到。
int sum = accumulate(vec.begin(),vec.end(),41);
得到的sum是将vec所有元素求和再加41。
这个函数也可以用来连接string型vector容器中元素:
string sum=accumulate(v.begin(),v.end(),string(""));
注意这时第三个变量一定是string类型,不能是字符串字面值,原因可以参考我的另一个博客《C++与C字符串对比》。
size_t cnt=0;
list<string>::iterator it=roster1.begin();
while((it=find_first_of(it,roster1.end(),
roster2.begin(),roster2.end()))
!=roster1.end()){
++cnt;
++it;
}
cout << "Found" << cnt
<< "names on both rosters" <<endl
fill(vec.begin(),vec.end(),0);
fill(vec.begin(),vec.begin()+vec.size()/2,10);
本质上是安全的,只会写入与输入范围同样数量的元素,哪怕是空容器,该函数只会对输入范围中已存在元素进行写操作。
vector<int> vec; //空容器
fill_n(vec.begin(),10,0); //灾难性错误,无法写入空容器
fill_n(back_inserter(vec),10,0);
效果相当于在vec上调用push_back。
vector<int> ivec;
copy(list.begin(),list.end(),back_inserter(ivec));
相当于把list复制到ivec后面。
这个方式效率较低,要创建一个已存在容器的副本可以用下面的方式:
vector<int> ivec(list.begin(),list.end());
vector<int> ivec;
replace(ilist.begin(),ilist.end(),0,41);
replace_copy(list.begin(),list.end(),back_inserter(ivec),0,41)
举个例子, words是字符串容器:
the quick red fox jumps over the slow red turtle
sort(words.begin(),words.end());
上述代码作用后,vector的元素按字典序排列:
fox jumps over quick red red slow the the turtle
其中red和the重复。
vector<string>::iterator end_unique=unique(words.begin(),words.end());
使用unique函数后并未删除重复,只是把重复的元素放到最后,此处返回end_unique。
此时原来的vector变成了:
fox jumps over quick red slow the turtle red the
最后使用erase删除重复:
words.erase(end_unique,words.end());
得到:
fox jumps over quick red slow the turtle
即使没有重复的元素,调用erase也是安全的,因为如果不存在重复,unique返回的是words.end(),也就是说需要删除的范围为空。类似的函数还有.remove(val)和.reverse()。
bool isShorter(const string &s1, const string &s2)
{
return s1.size()<s2.size();
}
bool GT6(const string &s)
{
return s.size()>=6;
}
对上面的排序去重的字符串容器使用stable_sort:
stable_sort(words.begin(),words.end(),GT6);
调用后words中元素按长度排列,但是长度相同的单词仍保持字典序。
用count_if统计长度不小于6的单词:
vector<string>::size_type wc =
count_if(words.begin(),words.end(),GT6);
类似的还有find_if、.remove_if(pred)函数,这类函数通常多一个参数,需要输入一个谓词。
list<int> ilist1,ilist2,ilist3;
for(list<int>::size_type i=0;i!=4;++i)
ilist1.push_fornt(i); //ilist1为3 2 1 0
copy(ilist1.begin(),ilist1.end(),front_inserter(ilist2)); //ilist2为0 1 2 3
copy(ilist1.begin(),ilist1.end(),inserter(ilist3,ilist3.begin())); //每次在固定位置插入,ilist3结果是3 2 1 0
istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
while(in_iter!=eof)
vec.push_back(*in_iter++);
上面的代码可以用下面的更简洁代码代替:
istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
vector<int> vec(in_iter,eof);
使用ostream_iterator的例子:
ostream_iterator<string> out_iter(cout,"\n");
istream_iterator<string> in_iter(cin),eof;
while(in_iter!=eof)
*out_iter++=*in_iter++;
该段程序读cin,将结果输出到cout不同行中。
与算法一起使用流迭代器:
istream_iterator<int> cin_it(cin);
istream_iterator<int> end_of_stream;
vector<int> vec(cin_it,end_of_stream);
sort(vec.begin(),vec.end());
ostream_iterator<int> output(cout," "); //定义输出流迭代器
unique_copy(vec.begin(),vec.end(),output); //将vector中的内容去重复制到输出流
string::iterator comma=find(line.begin(),line.end(),',');
cout<<string(line.begin(),comma)<<endl;
但是如果用反向迭代器想要输出最后一个单词,类似的代码输出将是倒序的,想要输出正序的最后一个单词,可以这样写:
string::iterator comma=find(line.rbegin(),line.rend(),',');
cout<<string(comma.base(),line.end())<<endl; //.base()返回逗号后一个元素位置,此处line.end()不能换成line.rbegin(),因为指向的位置不同
lst.merge(lst2);
lst.merge(lst2,comp);//将lst2的元素合并到lst中,两个容器都必须排序,用前一个函数必须是顺序,后一个使用comp谓词进行比较
lst.remove(val);
lst.remove_if(pred);//使用lst.erase删除所有等于指定值或者谓词返回不为1的值
lst.reverse();//反向排列
lst.splice(iter,lst2);
lst.splice(iter,lst2,iter2);
lst.splice(iter,beg,end);//第一个版本将lst2中所有元素移到lst的iter前,第二个版本只移动iter2指向的元素,这种情况下lst2和lst可以是同一个list,第三个版本移动beg和end范围内的元素,这个范围也可以是lst中的一部分