使用泛型算法必须包含algorithm头文件:
#include<algorithm>;
标准库还定义了一组泛化的算术算法,使用这些算法则必须包含numberic头文件
#include<numeric>
1. 只读算法
- find(vec.begin(),vec.end(),search_value)
- 使用两个迭代器和一个值调用find函数,检查两个迭代器实参标记范围内的每一个元素,只要找到与给定值相等的元素,find就会返回指向该元素 的迭代器。
- int sum = accumulate(vec.begin(),vec.end(),42);
- accumulate函数将它的一个内部变量设置为指定的初值,然后在此初值上累加输入范围内所有元素的值。accumulate算法返回累加的结果,其返回类型就是其第三个实参的类型。用于指定累加初始值的第三个实参是必要的,因为accumulate对将要累加的元素类型一无所知,因此,除此之外,没有别的办法创建合适的起始值或者关联的类型。
- find_first_of:
- 功能描述:在第一段范围内查找与第二段范围中任意元素匹配的元素,然后返回一个迭代器,指向第一个匹配的元素。如果找不到匹配,则返回第一个范围的end迭代器。示例如下:
size_t cnt;
list<string>::iterator iter = roster1.begin();
while( (iter = find_first_of(iter, roster1.end(),roster2.begin(),roster2.end())) !=roster1.end() ){
++cnt;
++iter;
}
cout << "Found " << cnt << " name on both rosters" << endl;
2. 写容器元素的算法
- 写入输入序列的元素
- fill(vec.begin(), vec.end(), 10);
- fill带有一对迭代器形参,用于指定要写入的范围,而所写的值是它的第三个形参的副本。如果输入范围有效,则可安全写入。
- fill(vec.begin(), vec.end(), 10);
- 不检查写入操作的算法
- fill_n(vec.begin(), 10, 0);
- 该函数从迭代器指向的元素开始,将指定数量的元素设置为给定的值。
- fill_n(vec.begin(), 10, 0);
- 引入back_inserter
back_inserter生成一个绑定在该容器上的插入迭代器。在试图通过这个迭代器给元素赋值时,赋值运算将调用push_back在容器中添加一个具有指定值的元素。示例如下:
vector<int> vec;
fill_n(back_inserter(vec), 10, 0);
实现效果相当于在vec末尾添加10个元素,每个元素的值都是0.
- 写入到目标迭代器的算法
vector<int> ivec;
copy(ilst,begin(), ilst.end(), back_inserter(ivec));
这个例子的效率比较差,更好的方法是直接用输入范围作为新构造容器的初始化:
vector<int> ivec(ilst.begin(), ilst.end());
- 算法的_copy版本
vector<int> ivec;
replace_copy(ilst.begin(), ilst,end(), back_inserter(ivec), 0, 42);
调用该函数后,ilst没有改变,ivec存储ilst的一份副本,而ilst内所有的0在ivec中都变成了42.
3 对容器元素重新排序的算法
bool isShorter(const string &s1, const string &2){
return s1.size() < s2.szie();
}
bool GT6(const string &s){
reutrn s.size() >= 6;
}
int main(){
vector<string> words;
string next_word;
while(cin >> next_word){
words.push_back(next_word);
}
sort(words.begin(), words.end());
vector<string>::iterator end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
stable_sort(words.begin(), words.end(), isShorter);
vector<string>::size_type wc = count_if(words.begin(), words.end(), GT6);
cout << wc << " " << make_plural(wc, "word", "s") << " b characters or longer" << endl;
return 0;
}
words中的单词排好序后,调用unique返回一个迭代器,指向超出无重复的元素范围末端的下一位置,即表示无重复的值范围的结束。函数isShorter和GT6分别是函数stable_sort和count_if的谓词。
4 再谈迭代器
容器除了普通的迭代器以外,C++还提供了另外三种迭代器:
- 插入迭代器(inster iterator)
- 实现在容器中插入元素的功能。
- iostream迭代器(iostream iterator)
- 与输入输出流绑定在一起,用于迭代遍历所关联的IO流。
- 反向迭代器(reverse iterator)
- 由rbegin和rend成员函数返回
4.1 插入迭代器
调用这三个函数都能生成一个迭代器:
- back_inserter:生成使用push_back实现插入的迭代器
- front_inserter:生成使用push_front实现插入的迭代器
- inserter :生成使用insert函数实现插入的迭代器,除了所关联的容器外,inserter还带有第二个实参:指向插入起始位置的迭代器(该迭代器指向位置不变)
用法示例如下:
list<int> ilst, ilst2, ilst3;
//after this loop,ilst contains 3 2 1 0
for(list<int>::size_type i=0;i!=4;++i)
ilst.push_front(i);
//after copy,ilst2 contains 0 1 2 3
copy(ilst.begin(), ilst.end(), front_inserter(ilst2));
//after copy,ilst3 contains 3 2 1 0
copy(ilst.begin(), ilst.end(), inserter(ilst3, ilst3.begin()));
4.2 iostream迭代器
- iostream迭代器的构造函数(头文件iterator)
- istream_iterator<T> in(strm)
- 创建从输入流strm读取T类型对象的istream_iterator对象
- istream_iterator<T> in;
- 未关联输入流,默认为istream_iterator对象的超出末端迭代器
- ostream_iterator<T> out(strm)
- 创建将T类型的对象写到输出流strm的ostream_iterator对象
- ostream_iterator<T> out(strm, delim)
- 创建将T类型的对象写到输出流strm的ostream_iterator对象,在写入过程中使用delim作为元素的分割符。delim是以空字符结束的字符数组。
- istream_iterator<T> in(strm)
- 示例一
istream_iterator<int> cin_it(cin);
istream_iterator<int> end_of_stream;
//使用迭代器范围初始化ivec
//vector<int> ivec(cin_it, end_of_stream);
while(cin_it != end_of_stream){
ivec.push_back(*cin_it++);
}
for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)
cout << *iter << endl;
- 示例二
ostream_iterator<string> out_iter(cout, "\n");
istream_iterator<string> cin_it(cin), eof;
while(cin_it != eof){
*out_iter++ = *cin_it++;
}
注解:当绑在流上的迭代器在遇到文件结束或者某个错误时,将等于超出末端迭代器的值。
4.3 反向迭代器
- 由于不能反向遍历流,因此流迭代器不能创建反向迭代器。
- 反向迭代器的几个示例:
string:reverse_iterator rcomma = find(line.rbegin(), line.rend(), ',');
cout << string(line.rbegin(), rcomma) << endl;
假设字符串line的值为hello,world,则以上程序的输出为:dlrow.这是因为反向迭代器是逆序从后向前处理string对象。为了得到争取的输出,可以采用反向迭代器提供的成员函数base,用法如下:
cout << string(rcomma.base(), line.end()) << endl;
得到正确的输出:world。
4.4 const_iterator:只读迭代器
5. 五种迭代器
算法要求的迭代器操作分为五个类别,分别对应如下五中迭代器:
- 输入迭代器
- 只能读不能写;只支持自增运算
- 输出迭代器
- 只能写不能读;只支持自增运算
- 前向迭代器
- 读和写;只支持自增运算
- 双向迭代器
- 读和写;支持自增和自减运算
- 随机访问迭代器
- 读和写;支持完整的迭代器算术运算
- 6. list容器特有的操作
- lst.merge(lst2)
- lst.merge(lst2, comp)
- lst.remove(va)
- lst.remove_if(unaryPred)
- lst.reverse()
- lst.sort()
- lst.splice(iter, iter2)
- lst.splice(iter, lst2, iter2)
- lst.splice(iter, begin, end)
- lst.unique()
- lst.unique(binaryPred)
具体用法和含义略。