CH10 泛型算法
概述
大多数算法都定义在algorithm头文件中。
Note:算法永远不会执行容器操作
泛型算法本身不会执行容器的操作,而是通过迭代器来访问、修改等操作
10.1
题目要求读取数据存入vector,并实现用户可以查找的值出现在vector中的次数,所以可以考虑用户查找文件中某个数出现的次数,所以可以考虑文件操作
1 int main(int argc, char* argv[]) 2 { 3 ifstream infile(argv[1]); 4 if (!infile) 5 cerr << "can not open the file!" << endl; 6 vector <int> iv; 7 int num; 8 while (infile >> num) 9 iv.push_back(num); 10 cout << "please enter the number you want to find" << endl; 11 int val; 12 cin >> val; 13 cout << "the count number " << val << " is :" << count(iv.begin(), iv.end(), val) << endl; 14 15 system("pause"); 16 return 0; 17 }
10.2
同上,只是,程序区别大小写
1 #include <iostream> 2 #include <algorithm> 3 #include <list> 4 #include <string> 5 #include <fstream> 6 7 using namespace std; 8 9 int main(int argc, char*argv[]) 10 { 11 ifstream infile(argv[1]); 12 if (!infile) 13 { 14 cerr << "can not open the file,please check" << endl; 15 return -1; 16 } 17 list<string>sl; 18 string words; 19 while (infile >> words) 20 sl.push_back(words); 21 string word; 22 cout << "please enter the word you want to count" << endl; 23 cin >> word; 24 cout <<"the number of "<<word<<" is :"<< count(sl.begin(), sl.end(), word) << endl; 25 26 }
只读算法
对于只读算法,通常最好使用cbegin()和cend(),但是如果用算法返回的迭代器来改变元素的值,就需要使用begin()和end()的结果作为参数
那些只接受一个单一迭代器来表示第二个序列的算法,都家丁第二个序列至少与第一个序列一样长。
10.3
accumulate(iv.begin(),iv.end(),0)
10.4
accumulate()将第三个参数作为求和的起点,序列中的元素的类型与第三个参数类型匹配,这里第三个是int型,所以前两个会被转换为int型。
写容器算法
一些算法从两个序列中读取元素。构成这两个序列的元素可以来自于不同类型的容器。例如,第一个序列可能保存于一个vector,而第二个可能保存于一个list、deque,内置数组或其他容器中。而且,两个序列中元素的类型也不要求严格匹配。
算法不检查写操作
1 fill_n(vec.begin(), vec.size(), 0);//将所有元素重置为0
back_insert:接受一个容器的引用,返回一个与该容器绑定的插入迭代器,当通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中
1 vector<int> vec; 2 auto it = back_insert(vec);//通过它赋值会将元素添加到vector中 3 *it = 42;//vec 中现在有一个元素42
copy算法:向目的位置的迭代器指向的输出序列中元素写入数据,接受三个迭代器,一对输入范围,第三个目的序列其实位置。
1 //使用copy实现内置数组的拷贝 2 int a1[] = { 0,1,2,3,4,5,6,7,8,9 }; 3 int a2[sizeof(a1) / sizeof(*a1)];//a2与a1大小相同 4 auto ret = copy(a1, begin(), a1.end(), a2);//使用copy将a1内容拷贝给a2,ret指向拷贝到 5 //a2的尾元素之后的位置
重排容器元素的算法
sort:接受一对迭代器,表示排序的范围, 按字典顺序排序
unique 重排输入范围,使得每个单词只出现一次
插入迭代器
插入迭代器(insert iterator)迭代器适配器,接受一个容器,生成一个迭代器,该迭代器使用容器操作箱给定容器添加元素。有3个创建插入迭代器的模板:
back_inserter:在类型为T的容器末尾添加元素,创建一个使用push_back的迭代器
front_inserter :容器头部插入元素,创建一个使用push_front的迭代器
inserter:创建一个insert的迭代器,该函数接受两个参数,第二个参数是一个指向容器的迭代器,元素被插入到给定迭代器表示的元素之前
当调用inserter(c,iter)时,c是绑定的容器,得到一个迭代器,使用它时,会将元素插入到iter原来所指向的元素之前的位置。如果it是由inserter生成的迭代器,则下面的语句
*it = val;
效果与下面代码一样
it = c.insert(it, val);
++it;
front_inserter生成的迭代器的行为与inserter生成迭代器不同,front_inserter总是插入到容器的第一个元素之前。
1 #include <iostream> 2 #include <vector> 3 #include <list> 4 #include <algorithm> 5 #include <iterator> 6 7 using namespace std; 8 9 int main() 10 { 11 vector<int> iv1 = { 1,2,3,4,5 }; 12 vector<int>iv2; 13 vector<int>iv3; 14 vector<int> iv4 = { 6,7 }; 15 copy(iv1.cbegin(), iv1.cend(), back_inserter(iv2)); 16 for (auto it : iv2) 17 cout << it << " "; 18 cout << endl; 19 copy(iv1.cbegin(), iv1.cend(), inserter(iv4, iv4.begin())); 20 for (auto it : iv4) 21 cout << it << " "; 22 cout << endl; 23 24 copy(iv1.cbegin(), iv1.cend(), inserter(iv3, iv3.begin())); 25 for (auto it : iv3) 26 cout << it << " "; 27 cout << endl; 28 list<int> il1 = { 1,2,3,4,5 }; 29 list<int>il2; 30 list<int>il3; 31 copy(il1.cbegin(), il1.cend(), front_inserter(il2)); 32 for (auto it : il2) 33 cout << it << " "; 34 cout << endl; 35 copy(il1.cbegin(), il1.cend(), inserter(il3, il3.begin())); 36 for (auto it : il3) 37 cout << it << " "; 38 cout << endl; 39 system("pause"); 40 return 0; 41 }
iostream 迭代器
iostream类型不是容器,标准库定义了可用于这些IO类型对象的迭代器
istream_iterator :读取输入流,
ostream_iterator: 想一个输出流写数据
创建一个流迭代器时,必须指定迭代器将要读写的数据的类型。一个istream_iterator使用>>读取流,所以istream_iterator要读取的数据类型必须定义了输入运算符>>.
istream_iterator<int> int_it(cin);//从cin读取int
istream_iterator<int> int_eof;//默认初始化迭代器,初始化为尾后迭代器
ifstream infile("a_file"); istream_iterator<string> str_it(infile);//使用istream_iterator从a_file读取数据
下面是一个使用istream_iterator从cin读取数据存入vector 的例子
1 istream_iterator<int> in_iter(cin); 2 istream_iterator<int>eof; 3 vector<int>vec; 4 while (in_iter != eof) 5 vec.push_back(*in_iter++);
测试结果
使用迭代器范围更为简洁
vector<int>vec(in_iter, eof);
测试结果
使用算法操作流迭代器
使用一对istream_iterator 调用accumulate:
istream_iterator<int> in_iter(cin); istream_iterator<int>eof; cout << accumulate(in_iter, eof, 0) << endl;
此调用会计算从标准输入读取的值的和。
ostream_iterator操作
可以对任何具有输出运算符<<的类型定义ostream_iterator。当创建一个ostream_iterator时,可以提供第二个参数。
ostream_iterator<T>out(os);//out将类型为T的值写到输出流os中 ostream_iterator<T>out(os, d);//out将类型为T的值写到输出流os中,每个值后面都输出一个d,d指向一个 //空字符串结尾的字符数组
使用ostream_iterator输出序列
ostream_iterator<int> out_iter(cout, " "); for (auto e : vec) *out_iter++ = e;//赋值语句将元素写入到cout cout << endl;
当向out_iter赋值时,可以忽略解引用和递增运算,即,循环可以写成下面这样
for (auto e : vec) out_iter = e;//赋值语句将元素写入到cout cout << endl;
但是推荐第一种形式,流迭代器的使用和其它迭代器的使用保持一致
//调用copy打印,比循环更简洁 copy(vec.begin(), vec.end(), out_iter); cout << endl;
10.29
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <iterator> 5 #include <fstream> 6 using namespace std; 7 8 int main(int argc, char*argv[]) 9 { 10 ifstream infile(argv[1]); 11 if (!infile) 12 { 13 cerr << "can not open the file" << endl; 14 return -1; 15 } 16 istream_iterator<string>str_in_iter(infile);//从输入文件流infile读取数据 17 istream_iterator<string>eof; 18 vector<string>svec(str_in_iter, eof); 19 ostream_iterator<string>str_out_iter(cout, " "); 20 for (auto e : svec) 21 *str_out_iter++ = e; 22 23 cout << endl; 24 25 system("pause"); 26 return 0; 27 }
测试结果
10.30 10.31
1 #include <iostream> 2 #include <vector> 3 #include <fstream> 4 #include <algorithm> 5 #include <iterator> 6 7 using namespace std; 8 9 int main() 10 { 11 istream_iterator<int> in_it(cin); 12 istream_iterator<int> eof; 13 vector<int>iv; 14 while (in_it != eof) 15 iv.push_back(*in_it++); 16 sort(iv.begin(), iv.end()); 17 18 ostream_iterator<int>out_it(cout, " "); 19 copy(iv.begin(), iv.end(), out_it); 20 cout << endl; 21 //10.31 22 unique_copy(iv.begin(), iv.end(), out_it); 23 system("pause"); 24 return 0; 25 }
10.33
1 #include <iostream> 2 #include <iterator> 3 #include <fstream> 4 5 using namespace std; 6 7 8 int main(int argc, char*argv[]) 9 { 10 if (argc != 4) 11 cerr << " the number of files is not correct" << endl; 12 ifstream infile(argv[1]); 13 if (!infile) 14 { 15 cerr << "can not open the file " << endl; 16 return -1; 17 } 18 19 ofstream odd_out(argv[2]); 20 if (!odd_out) 21 cerr << "can not open the file or the file does not exist" << endl; 22 ofstream even_out(argv[3]); 23 if(!even_out) 24 cerr << "can not open the file or the file does not exist" << endl; 25 26 istream_iterator<int> in_iter(infile); 27 istream_iterator<int> eof; 28 /*ostream_iterator<int>out_iter_odd(cout, " "); 29 ostream_iterator<int>out_iter_even(cout, " ");*/ 30 ostream_iterator<int>out_iter_odd(odd_out, " "); 31 ostream_iterator<int>out_iter_even(even_out, " "); 32 while (in_iter != eof) 33 { 34 if (*in_iter % 2) 35 *out_iter_odd++ = *in_iter; 36 else 37 out_iter_even++ = *in_iter; 38 in_iter++; 39 } 40 41 system("pause"); 42 return 0; 43 }