CH10 泛型算法

Posted Emma_U

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

以上是关于CH10 泛型算法的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer笔记10---chapter10 泛型算法

Chapter10:泛型算法

操作 Java 泛型:泛型在继承方面体现与通配符使用

这个嵌套类构造函数片段可以应用于泛型类吗?

泛型算法C++

算法笔记--快读(输入外挂)模板