C++复习 11 泛型算法
来源:互联网 发布:服务器udp优化加速 编辑:程序博客网 时间:2024/06/06 12:41
声明,所有的朋友,如果要转我的帖子,务必注明"作者:黑啤来源:CSDN博客"和 具体的网络地址http://blog.csdn.net/nx500/archive/2007/10/24/1842403.aspx,并且我的所有 博客内容,禁止任何形式的商业用途,请大家尊重我的劳动.谢谢!
目 录
十一.泛型算法.
001 标准库没有为每种容器类型都定义实现各种操作的成员函数,而是定义了一组泛型算法.
因为他们实现共同的操作,所以称为算法;因为他们可以操作在多种容器类型上,所以称为泛型.
泛型算法从不执行容器的操作,只是单独依赖迭代器和迭代器操作实现.
使用泛型算法必须先包含algorithm头文件.使用泛化的算术算法则必须包含numeric头文件.
#include <algorithm>
#include <numeric>
002 find.在两个迭代器中搜索指定元素.
int search_value = 42;
vector<int>::const_iterator result = find(vec.begin(), vec.end(), search_value);
003 累加指定范围元素的和,通过第三个元素,传递泛型算法针对的元素类型.
int sum = accumulate(vec.begin(), vec.end(), 0);
使用accumulate把string型的vector容器中的元素连接起来.
string sum = accumulate(vStr.begin(), vStr.end(), string(""));
004 将元素写入容器的算法.
使用迭代器确定写入的范围,这样操作可以通过迭代器保证写入的范围是有效的.
fill(vec.begin(), vec.end(), 0); // 将vec的元素都设置为0.
不检查写入范围的算法,可能越界,造成意想不到的后果.
fill_n(vec.gegin(), 10, 0);
使用插入迭代器防止越界,使用back_inserter必须包含iterator头文件.
vector<int> vec; // 声明一个空容器.
fill_n(back_inserter(vec), 10, 0); // fill_n每写入一个函数,都会通过back_inserter生成的插入迭代器实现.
向目标迭代器写入未知个数的元素.
vector<int> ivec;
copy(ilist.begin(), ilist.end(), back_inserter(ivec)); // 将ilist中的元素copy到ivec中
// 以上代码只是举例,更有效率的办法是初始化时赋值 vector<int> ivec(ilist.begin(), ilist.end());
改变输入序列的算法.
replace(ilst.begin(), ilst.end(), 0, 42); // 将ilst序列中0元素换为42.
// 下面一行ilst容器中元素不变,在ivec中保存一份ilst的副本,但是ilst中的0,在lvec中都是42.
replace(ilst.begin(), ilst.end(), back_inserter(ivec), 0 , 42);
005.对容器元素重新排序.
分析一组单词,求它们一共包含了多少个6个或6个以上字母组成的单词,每个单词只统计一次,不考虑重复情况.
// 将words中的元素(单词)安字母顺序排序.
sort(words.begin(), words.end());
// 将排序后的words只保留一个单词的副本,也就是将重复的单词删除.
// unique可以将没有重复的单词复制到容器的前端,比 "aa bb bb cc dd dd c" 变成"aa bb cc dd dd dd c".
// 同时unique返回一个指针,指向最后一个不重复的单词的下一个元素,上边的例子就是指向倒数第三个元素.所以...
vector<string>::iterator end_unique = unique(word.begin(), word.end());
words.erase(end_unique, words.end());
// stable_sort算法,排序后结果保留相等元素的原始相对位置,它支持谓词(自定义函数),自定义一个长度相等的函数替换元素的==操作符.
// 这个函数必须带有两个实参,每个实参都是元素的类型,并且返回一个bool型结果.
bool isShorter(const string& s1, const string& s2){
return s1.size() < s2.size();
}
stable_sort(words.begin(), words.end(), isShorter);
// count_if算法,比count算法多一个统计条件(谓词),这个谓词要求带一个元素类型的实参,返回一个bool的结果.
class GT{
std::string::size_type bound;
public:
GT(int sz = 0):bound(sz){}
bool operator()(const string& s){
return s.size() >= bound
}
};
vector<string>::size_type wc = count_if(words.begin(), words.end(), GT(6));
// 程序11005.cpp
#include <iostream>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
// 创建复数形式
string make_plural(size_t ctr, const string &word, const string &ending){
return (ctr == 1) ? word : word + ending;
}
// 定义stable_sort算法的谓词函数.
bool isShorter(const string& s1, const string& s2){
return s1.size() < s2.size();
}
// 定义count_if算法的谓词函数类
class GT{
string::size_type bound;
public:
GT(int sz = 0):bound(sz){}
bool operator()(const string& s){
return s.size() >= bound;
}
};
int main(){
vector<string> words;
string next_word;
// 从键盘终端读入待统计的单词
while(cin >> next_word){
words.push_back(next_word);
}
// 将words中的元素(单词)按字母顺序排序.
sort(words.begin(), words.end());
// 将排序后的words只保留一个单词的副本,也就是将重复的单词删除.
vector<string>::iterator end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
// 将words按照单词长度排序, 经过部分验证,没有这一步不影响统计结果.
stable_sort(words.begin(), words.end(), isShorter);
// 统计长度大于等于6的单词长度.
vector<string>::size_type wc = count_if(words.begin(), words.end(), GT(6));
cout << wc << " " << make_plural(wc, "word", "s")
<< " 6 characters or longer" << endl;
for(vector<string>::const_iterator it = words.begin(); it != words.end(); ++it){
cout << *it << " ";
}
return 0;
}
#include <iostream>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
// 创建复数形式
string make_plural(size_t ctr, const string &word, const string &ending){
return (ctr == 1) ? word : word + ending;
}
// 定义stable_sort算法的谓词函数.
bool isShorter(const string& s1, const string& s2){
return s1.size() < s2.size();
}
// 定义count_if算法的谓词函数类
class GT{
string::size_type bound;
public:
GT(int sz = 0):bound(sz){}
bool operator()(const string& s){
return s.size() >= bound;
}
};
int main(){
vector<string> words;
string next_word;
// 从键盘终端读入待统计的单词
while(cin >> next_word){
words.push_back(next_word);
}
// 将words中的元素(单词)按字母顺序排序.
sort(words.begin(), words.end());
// 将排序后的words只保留一个单词的副本,也就是将重复的单词删除.
vector<string>::iterator end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
// 将words按照单词长度排序, 经过部分验证,没有这一步不影响统计结果.
stable_sort(words.begin(), words.end(), isShorter);
// 统计长度大于等于6的单词长度.
vector<string>::size_type wc = count_if(words.begin(), words.end(), GT(6));
cout << wc << " " << make_plural(wc, "word", "s")
<< " 6 characters or longer" << endl;
for(vector<string>::const_iterator it = words.begin(); it != words.end(); ++it){
cout << *it << " ";
}
return 0;
}
006 除容器本身的迭代器之外,C++提供额外三种迭代器:插入迭代器/iostream迭代器/反向迭代器,他们都包含在<iterator>头文件中.
007 三种插入迭代器.插入器其实是一个迭代器的适配器,带有一个容器的参数,生成一个迭代器,用于在指定的容器中插入元素.
back_inserter,创建使用push_back实现插入的迭代器.
vector<int> vec; // 声明一个空容器.
fill_n(back_inserter(vec), 10, 0); // fill_n每写入一个函数,都会通过back_inserter生成的插入迭代器实现.
front_inserter,是push_front实现插入,所以vector是不能使用这个插入器的.
inserter,使用insert是实现插入操作,除了所关联的容器作为第一个参数外,还有一个指向插入起始位置的迭代器参数.
// 在ilst容器中元素为42前插入ivec的全部元素,并将ivec中值为100的元素替换为0.
list<int>::iterator it = find(ilst.begin(), ilst.end(), 42);
replace_copy(ivec.begin(), ivec.end(), inserter(ilst, it), 100, 0);
inserter和front_inserter的行为有很大差别.在使用front_inserter时,元素始终在容器的第一个元素前面插入.
而使用inserter,元素则在指定位置前面插入.如果这个位置是容器的第一个元素,插入一个新元素后,它就不在是第一个元素了.
#include <iostream>
#include <list>
#include <algorithm>
#define SIZE 4
using std::list;
using std::cout;
using std::endl;
using std::front_inserter;
using std::inserter;
// 输出指定迭代器之间的元素
void printList(list<int>::const_iterator begin, list<int>::const_iterator end){
while (begin != end){
cout << *begin << " ";
++begin;
}
cout << endl;
}
// 11007.cpp 验证front_inserter和inserter之间的不同.
int main(void){
list<int> ilst, ilst2, ilst3;
// 创建原始数据序列 3 2 1 0.
for(list<int>::size_type i = 0; i != SIZE; ++i){
ilst.push_front(i);
}
// 使用front_inserter插入器,形成0 1 2 3 序列.
copy(ilst.begin(), ilst.end(), front_inserter(ilst2));
// 使用inserter在ilst3.begin()这个位置插入,这个位置是指第一次插入前固定的位置.
// 不是每插入一个元素都运行一次ilst3.begin(),所以形成3 2 1 0序列.
copy(ilst.begin(), ilst.end(), inserter(ilst3, ilst3.begin()));
printList(ilst.begin(), ilst.end());
printList(ilst2.begin(), ilst2.end());
printList(ilst3.begin(), ilst3.end());
return 0;
}
#include <list>
#include <algorithm>
#define SIZE 4
using std::list;
using std::cout;
using std::endl;
using std::front_inserter;
using std::inserter;
// 输出指定迭代器之间的元素
void printList(list<int>::const_iterator begin, list<int>::const_iterator end){
while (begin != end){
cout << *begin << " ";
++begin;
}
cout << endl;
}
// 11007.cpp 验证front_inserter和inserter之间的不同.
int main(void){
list<int> ilst, ilst2, ilst3;
// 创建原始数据序列 3 2 1 0.
for(list<int>::size_type i = 0; i != SIZE; ++i){
ilst.push_front(i);
}
// 使用front_inserter插入器,形成0 1 2 3 序列.
copy(ilst.begin(), ilst.end(), front_inserter(ilst2));
// 使用inserter在ilst3.begin()这个位置插入,这个位置是指第一次插入前固定的位置.
// 不是每插入一个元素都运行一次ilst3.begin(),所以形成3 2 1 0序列.
copy(ilst.begin(), ilst.end(), inserter(ilst3, ilst3.begin()));
printList(ilst.begin(), ilst.end());
printList(ilst2.begin(), ilst2.end());
printList(ilst3.begin(), ilst3.end());
return 0;
}
008 虽然iostream类型不是容器,但是标准库同样提供了在iostream对象上使用的迭代器.这些迭代器将它们所对应的流视为特定类型的元素序列.
istream_iterator<T> it(strm); 创建从输入流strm中读入T类型对象的istream_iterator对象.
istream_iterator<T> it; 创建istream_iterator对象的超出末端迭代器.
ostream_iterator<T> it(strm); 创建将类型T的对象写到流ostream_iterator对象.
ostream_iterator<T> it(strm, delim); 创建将类型T的对象写到流strm的ostream_iterator对象,写入过程中用delim分割.
流迭代器定了基本的迭代器操作,自增/解引用/赋值,两istream可以比较是否相等,但ostream迭代器不能比较.
定义流迭代器.
istream_iterator<int> cin_it(cin); // 从cin中读入int类型对象.
istream_iterator<int> eof; // 输入流的末端指示迭代器.
// 创建一个Sales_item类型对象写入到ofstream流中的迭代器.
ofstream outfile;
ostream_iterator<Sales_item> output(outfile, " ");
istream_iterator对象上的操作.
// 将流上的对象逐个添加到容器中.
istream_iterator<int> cin_it(cin); // 从cin中读入int类型对象.
istream_iterator<int> eof; // 输入流的末端指示迭代器.
list<int> ilst;
while(cin_it != eof)
ilst.push_back(*cin_it++);
// 使用初始化的方式将流中的元素放到容器中.
vector<int> ivec(cin_it, eof);
ostream_iterator对象的操作.
// 写一个字符串字面值到cout流中.
ostream_iterator<string> out_it(cout, "hello heipi!");
// 读入cin流中的元素,并逐一写到cout流中去
istream_iterator<string> cin_it(cin), eof;
while(cin_it != eof)
*out_it++ = *cin_it++;
在类类型上使用istream_iterator.只要类型提供了输入操作符,就可以创建istream_iterator对象.
// 11008.cpp
#include <iostream>
#include <iterator>
#include "Sales_item.h"
#include "Sales_item.cpp"
using std::cin;
using std::cout;
using std::endl;
using std::istream_iterator;
int main(void){
// 定义Sales_item类型的输入流迭代器和超出末端迭代器.
istream_iterator<Sales_item> item_iter(cin), eof;
Sales_item sum;
// 从迭代器中读入第一个元素
sum = *item_iter++;
// 循环读入元素,如果不是同一本书,则输出前边的统计结果,然后开始统计新书的数据.
while(item_iter != eof){
if(item_iter ->same_isbn(sum))
sum += *item_iter;
else{
cout << sum << endl;
sum = *item_iter;
}
++item_iter;
}
cout << sum << endl;
return 0;
}
#include <iostream>
#include <iterator>
#include "Sales_item.h"
#include "Sales_item.cpp"
using std::cin;
using std::cout;
using std::endl;
using std::istream_iterator;
int main(void){
// 定义Sales_item类型的输入流迭代器和超出末端迭代器.
istream_iterator<Sales_item> item_iter(cin), eof;
Sales_item sum;
// 从迭代器中读入第一个元素
sum = *item_iter++;
// 循环读入元素,如果不是同一本书,则输出前边的统计结果,然后开始统计新书的数据.
while(item_iter != eof){
if(item_iter ->same_isbn(sum))
sum += *item_iter;
else{
cout << sum << endl;
sum = *item_iter;
}
++item_iter;
}
cout << sum << endl;
return 0;
}
//编译及运行结果
heipi@Linux:~/Documents/CPP> g++ -o o Sales_item.cpp 11008.cpp
heipi@Linux:~/Documents/CPP> ./o
9-99-999-8898 2 398
9-99-999-8898 3 453
9-88-888-8989 1 23
9-99-999-8898 5 2155 431
^d9-88-888-8989 1 23 23
heipi@Linux:~/Documents/CPP>
009 迭代器的限制.
1.不能从ostream_iterator对象读入,也不能写到istream_iterator.
2.一旦写入ostream_iterator对象,就不能从中删除了.
3.ostream_iterator没有->操作.
010 将流迭代器与算法一起操作.
// 11010.cpp 将输入流中的整形元素排序,并去掉重复项输出.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::istream_iterator;
using std::ostream_iterator;
int main(void){
// 从输入段读入元素,放到容器中.
istream_iterator<int> cin_it(cin), eof;
vector<int> vec(cin_it, eof);
// 排序,输出.
sort(vec.begin(), vec.end());
ostream_iterator<int> cout_it(cout, " ");
unique_copy(vec.begin(), vec.end(), cout_it);
cout <<endl;
return 0;
}
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
using std::istream_iterator;
using std::ostream_iterator;
int main(void){
// 从输入段读入元素,放到容器中.
istream_iterator<int> cin_it(cin), eof;
vector<int> vec(cin_it, eof);
// 排序,输出.
sort(vec.begin(), vec.end());
ostream_iterator<int> cout_it(cout, " ");
unique_copy(vec.begin(), vec.end(), cout_it);
cout <<endl;
return 0;
}
// 编译运行
heipi@Linux:~/Documents/CPP> g++ -o o 11009.cpp
heipi@Linux:~/Documents/CPP> ./o
1 2 3 43213 5625 5463 24134 676 13423 76356 211 2 3 4 5625
1 2 3 4 211 676 5463 5625 13423 24134 43213 76356
heipi@Linux:~/Documents/CPP>
011 反向迭代器(reverse_iterator),是一种反向遍历容器的迭代器.也就是从最后一个元素到第一个元素遍历容器.
注意反向迭代器标识的范围,特别是在输出上,小心陷阱.反向迭代提供一个成员函数base(),返回该迭代器按照正向方向的下一个元素的迭代器.
012 五种迭代器的操作.
1.输入迭代器只能顺序使用,一旦迭代器自增,就无法再用它检查之前的元素.
2.输出迭代器,对于指定的迭代器值因该使用一次*运算,而且只能使用一次.一般输出迭代器作为算法的第三个参数.
3.前向迭代器用于读写指定的容器,只会以一个方向遍历序列.可复制前向迭代器来记录序列的一个位置,以便将来返回此处.
4.双向迭代器.
5.随机访问迭代器,迭代器支持+/-n操作,下标[]操作.
map/set/list类型提供双向迭代器,而string/vector/deque容器定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机的.
istream_iterator是输入迭代器,而ostream_iterator是输出迭代器
尽管map和set类型提供双向迭代器,但关联容器只能使用算法的一个子集.因为关联容器的键值是const对象.
因此关联容器不能使用任何写序列元素的算法,只能使用与关联容器绑定在一起的迭代器来提供用于读操作的实参.
向算法传递无效的迭代器类别所引起的错误,编译时无法保证能发现.
- C++复习 11 泛型算法
- K&R复习,数据结构(C语言版)复习,算法导论复习
- 复习C++--分治算法--找出假币
- C语言复习笔记 11
- 算法复习
- 算法复习
- 算法复习
- 算法复习~
- C 复习
- C复习
- c复习
- C复习
- 复习C
- C复习
- 复习C语言算法——二分查找
- 重新复习C语言 大多数还是语法、算法的问题
- 【算法】生僻算法复习
- C复习笔记(浮点型数据)
- 过两天要去北京出差了,考虑中...
- OSDI, SOSP与美国著名计算机系的调查
- 用Eclipse对IDL中的函数编写测试用例心得
- 我们进复赛了!!(2007IBM主机全国大赛)
- Eclipse 常用插件下载地址
- C++复习 11 泛型算法
- 乡愁 余光中
- Java集合框架
- weblogic810-web-jar.dtd
- 最近迷茫了,不知道去哪家好
- 本地化、全球化、国际化测试
- 测试小技巧-黑盒测试
- MySQL中动态生成多条件查询语句
- Java连接access数据库