您的位置:首页 > 编程语言 > C语言/C++

C++ Primer 笔记+习题解答(十)

2015-02-08 18:03 281 查看
在昨天尝试了MarkDown编辑器后,我决定还是不尝新鲜,踏实的用老编辑器吧。今天第十个章节,主要内容是泛型算法。最近一直在思考,要不要把书上的一些基础知识搬到博客中,因为这样做我总有一种感觉叫抄书。后来我转念想了一下,还是抄书吧,毕竟你不是天赋异禀,抄书巩固记忆和理解。
若有错误 请指正 谢谢

0.引言:

在标准库中,为容器的定义的操作很少,

比如我们使用过的插入删除操作等。为了拓展其功能,标准库不在是单独为每个容器定义功能函数,而且通过定义一组泛型算法来让大多数容器都能用的上,着实很省力。

泛型:称之为泛型是因为其与容器的具体类型无关,算法操纵的一般是迭代器。

算法:称之为算法是因为他实现了一些经典算法的接口,比如排序查找等。

1.泛型算法概述:

1.大多数定义在头文件algorithm中,部分数值算法定义在numeric中。

2.使用迭代器范围实现泛型,不依赖于具体容器。但是要依赖容器中的元素类型。比如当你排序的时候,如果容器中的元素都不具备可比性,那么排序算法的调用也是无意义的。

3.泛型算法永远不会执行容器层面的操作(这个地方是指容器中的插入,删除等操作),它们运行于迭代器层面上。泛型算法不会改变容器的大小,可能会移动元素,修改元素,但是不会直接改变容器的大小。

2.初始泛型算法:

2.1只读算法:

只读书输入范围内的元素,从不修改它。

示例:

<span style="font-size:18px;"><span style="font-size:18px;">find(beg,end,var);</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">count 算法</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">accumulate算法。此算法是定义在numeric头文件中。原型:accumulate(beg,end,0);传入的0代表求和的初值。</span></span>
建议使用const_iterator.
<span style="font-size:18px;"><span style="font-size:18px;">equal算法:比较两个容器中的元素是否相等。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">不强调容器类型,强调元素类型。元素类型要定义==运算符。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">格式:equal(beg1,end1.beg2);beg2表示第二个输入范围的首位置。蕴含一个假定,第二个范围至少同第一个输入范围一样长。</span></span>


2.2 修改容器元素的算法:

<span style="font-size:18px;"><span style="font-size:18px;">fill(beg,end,var);讲var的值赋给容器范围内的没个元素。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">fill_n(dest,n,var); dest表示起始位置。从起始位置开始的n个元素被修改为var.前提是要有那么多元素可以写。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">修改操作是定义在赋值的基础上,所以决定了前提是容器中有东西。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">back_inserter,插入迭代器:</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">正常情况下我们使用迭代器,对迭代器进行解引用是执行了一种修改操作,前提是容器中的元素已经存在。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">但是插入迭代器的行为比较特殊,插入迭代器不指向具体的某个元素的位置,而是和容器绑定在一起。当我们对迭代器解引用并进行赋值的时候,我们实际上是把与等号右侧的元素添加到容器中,其中具体的实现方法是调用push_back成员函数实现的。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">插入迭代器定义在头文件iteraotr中。接受一个容器作为参数,返回一个插入迭代器。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">-----------------------</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">#include <list>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
<span style="white-space:pre">	</span>vector<int> ivec;
<span style="white-space:pre">	</span>auto it = back_inserter(ivec);
<span style="white-space:pre">	</span>fill_n(it, 10, 0);
<span style="white-space:pre">	</span>ostream_iterator<int> out(cout, " ");
<span style="white-space:pre">	</span>copy(ivec.cbegin(), ivec.cend(), out);
<span style="white-space:pre">	</span>system("pause");
<span style="white-space:pre">	</span>return 0;
}
</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">下面对比下不使用插入迭代器的时候会发生什么意外:</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">#include <list>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
<span style="white-space:pre">	</span>vector<int> ivec;
<span style="white-space:pre">	</span>fill_n(ivec.begin(), 10, 0);//fill_n算法。
<span style="white-space:pre">	</span>fill(ivec.begin(), ivec.end(), 10); //fill算法。
<span style="white-space:pre">	</span>ostream_iterator<int> out(cout, " ");
<span style="white-space:pre">	</span>copy(ivec.cbegin(), ivec.cend(), out);
<span style="white-space:pre">	</span>system("pause");
<span style="white-space:pre">	</span>return 0;
}</span></span>


<span style="font-size:18px;"><span style="font-size:18px;">copy算法:</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">copy(beg,end,beg1);三个迭代器参数,前两个表示输入范围,第三个迭代器表示目的序列的起始位置,同样蕴含编程假定,目的序列至少同输入范围序列一样大。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">返回尾后目的序列的尾后迭代器。</span></span>


<span style="font-size:18px;"><span style="font-size:18px;">replace算法:</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">replace(beg,end,oldvar,newvar);把输入序列中等于oldvar的替换为newvar.</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">如果希望保持原序列保持不变,那么可以使用replace_copy算法。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">#include <list>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
vector<int> ivec{ 1, 2, 3, 4, 5, 6, 5, 4, 3 };
<span style="white-space:pre">	</span>ostream_iterator<int> out(cout, " ");
<span style="white-space:pre">	</span>cout << "Print all elements : ";
<span style="white-space:pre">	</span>copy(ivec.cbegin(), ivec.cend(), out);
<span style="white-space:pre">	</span>//调用replace算法。
<span style="white-space:pre">	</span>cout << endl;
<span style="white-space:pre">	</span>replace(ivec.begin(), ivec.end(), 3, 99);//原序列中为3的元素全部修改为99。
<span style="white-space:pre">	</span>cout << "Now ,print all the elements : ";
<span style="white-space:pre">	</span>copy(ivec.cbegin(), ivec.cend(), out);
<span style="white-space:pre">	</span>cout << endl;
<span style="white-space:pre">	</span>vector<int> ivec2;
<span style="white-space:pre">	</span>replace_copy(ivec.begin(), ivec.end(), back_inserter(ivec2), 99, 3);
<span style="white-space:pre">	</span>cout << "Print the elements of ivec : ";
<span style="white-space:pre">	</span>copy(ivec.cbegin(), ivec.cend(), out);
<span style="white-space:pre">	</span>cout << endl;
<span style="white-space:pre">	</span>cout << "Print the elements of ivec2 : ";
<span style="white-space:pre">	</span>copy(ivec2.cbegin(), ivec2.cend(), out);
<span style="white-space:pre">	</span>system("pause");
<span style="white-space:pre">	</span>return 0;
}
</span></span>


2.3 重排容器元素的算法:

<span style="font-size:18px;"><span style="font-size:18px;">sort(beg,end);利用输入范围内的元素上定义的<运算实现。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">unique(beg,end);覆盖已经排序序列中的重复元素,是覆盖,不是删除。一旦执行了删除操作,容器的大小就被改变了,不符号初衷。</span></span>

3 定制操作:

3.1像算法传递函数:

谓词:可调用的表达式,返回可用做条件值,简单来说也就是布尔值。

STL中使用的谓词分为两类,谓词函数接受的参数个数来划分。一元谓词只接受一个参数,二元谓词接受两个参数。

接受谓词参数的算法会对输入范围内的元素调用此谓词函数,因为谓词函数中的形参类型必须要同序列中的 元素类型匹配。

示例:

<span style="font-size:18px;"><span style="font-size:18px;">sort(beg,end,short);
其中short是我们自己定义的函数,我们当作参数使用。
此时的排序算法会按照short函数中的定义进行。如果short是定义长度的比较,那么排序是按照长度进行的。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">如果希望长度一样的单词按照字典序排序,可以使用stable_sort(beg,end,short);</span></span>


3.2 Lambda表达式:

新语言的特性是因为出现了不好解决的问题。比如只接受一元谓词的算法却必须要传入两个参数,这个时候就必须变化了,变则通嘛。

可调用对象(Called object):对于一个对象或者表达式e,如果e可以出现在调用运算符的左侧,那么我们称e为可调用的。

目前我们已知的可调用对象是:函数,函数指针。还会接触的两个是重载调用运算符的类以及现在要介绍的lambda表达式。

lambda expression 的相关理解:

可调用的代码单元,匿名函数,内联函数。三个名次比较好的解释了lambda表达式,首先匿名是没用函数名的,可调用表明要具备一点函数的功能,内联函数表明代码应该是比较短小的,否则也不适合内联。

<span style="font-size:18px;"><span style="font-size:18px;">style:</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">[capture list](parameter list) ->return type { function body} </span></span>
<span style="font-size:18px;"><span style="font-size:18px;">第一部分是捕获列表,后面是形参表,接着的是尾置返回类型,最后是函数体。从这个地方也可以看出具备函数的大部分特征,只是没名字。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">捕获列表:通常可以省略,捕获的是使用lambda表达式的函数中定义的局部变量,不能是static。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">我们使用时可以忽略形参列表和返回类型,但是一定要有捕获列表或函数体。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">tips:lambda表达式用的比较关,刚刚介绍的谓词应该是主要用于STL算法中,但是lambda表达式任何地方都可以使用。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">示例:</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">#include <iostream>
using namespace std;
int main(){
<span style="white-space:pre">	</span>auto f = [](int i){return ++i; };
<span style="white-space:pre">	</span>cout << f(2)<<endl;  //此处的f是可以调用的。
<span style="white-space:pre">	</span>system("pause");
<span style="white-space:pre">	</span>return 0;
}
</span></span>
<span style="font-size:18px;"><span style="font-size:18px;"></pre><pre name="code" class="cpp">当我们省略返回类型 的时候,若lambda的表达式中只有一条return语句,那么函数可以根据return语句推测出返回值类型。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">若有多条语句,并且没用显式指定返回值类型,那么默认是void类型。</span></span>
向lambda传递参数:
不存在默认实参,符合普通的函数的初始化形参规则。

使用捕获列表:

捕获的是所在函内的局部变量,可以是形参中的,可以是函数体内的非static变量,在lambda函数体内可以使用局部static变量,也可以使用所在函数外定义的变量。

3.3 lambda的捕获和返回:

捕获相关:

类似参数传递,有值捕获和引用捕获。

隐式捕获:根据函数体中使用的变量进行推断捕获列表中内容。一般在捕获列表内写上=号表示隐式的值捕获,&表示隐式的引用捕获。

可以混合使用隐式捕获和显式捕获,但是要注意一些规则,具体规则可以翻书。

当值捕获遇到mutable:

通常来说,值捕获的时候,是不在函数体内修改捕获到变量的,但是想修改的时候可以加上mutable关键词。

在函数体内能否修改捕获的变量,取决于引用的对象是否局部const属性。

lambda的返回类型:

上面已经介绍过了,多天语句的时候最后显式的指定返回类型,而且记得用尾置返回类型。

3.4参数绑定:

来源于标准库的bind函数,是一种函数适配器机制。接受一个可调用对象,生成一个可调用对象来适应原参数列表的需求。

<span style="font-size:18px;"><span style="font-size:18px;">格式:auto newCallable=bind(Callable,arg_list);</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">其中的Callable和newCallable都是可调用对象。Callable经过bind函数适配过后,产生了一个新对象。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">其中的arg_list可能会包含占位符,形如_1,_2,之类的。这些占位符定义在命名空间placeholders中。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">所以这样的语句可能是必要的。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">using std::placeholders::_1;用一个定义一个,或者省事的办法是</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">using namespace std::placeholders;这样一次性都包含进去了。</span></span>
一般来说占位符表示的形参应该是输入范围要传入的元素,对于不变的量,直接放在bind函数里的形参表就可以了。
一般来说短小函数用lambda,如果大型函数可以考虑试试bind函数版定。这个之间存在一种映射关系,当调用新生成的对象时,会映射到原来的可调用对象上。

在bind函数的arg_lists上也 存在普通函数的传值问题。但是有的值是无法拷贝的,比如cout对象,这个时候出现了ref和cref函数。

一看就和引用相关。这个时候表示形参列表不在是拷贝了,而是引用传递。

4.迭代器再探:

除了为每个容器定义的迭代器,在头文件iterator中还定义了一些特殊用途的迭代器。

<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">1.insert iterator;
2.stream iterator;
3.reverse iterator;
4.move iterator;此迭代器用于移动元素而不是拷贝。</span></span>


4.1 插入迭代器:

<span style="font-size:18px;color:#330099;"><span style="font-size:18px;"><span style="font-size:18px;">三种插入迭代器:对应前面的成员操作,push_back,push_front,insert 三个操作。</span></span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;"><span style="font-size:18px;">三个操作对应的迭代器分别是:back_inserter,front_inserter,inserter。</span></span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;"><span style="font-size:18px;">三者的区别在于调用的底层容器函数不同。所以只有当对应的容器支持支持push_back函数时,你才可以使用back_inserter。</span></span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;"><span style="font-size:18px;">对于inserter,有两个参数,第一个是接受一个容器,第二个参数是指示位置。</span></span></span>

相关函数演示:

<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">copy(beg,end,back_inserter(vec));
copy(beg,end,inserter(vec,vec.begin());</span></span>


4.2 iostream_iterator:

讲对应的流当作一个特点的元素序列来处理。

分类:

<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">ostream_iterator 
istream_iterator;</span></span>
istream_iterator的操作:
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">istream_iterator<int> in_iter(cin); //从cin读取int.
istream_iterator<int> eof;  //可以当作尾后迭代器使用,此处未绑定流。</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">示例:</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">while(in_iter!=eof)</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">    vec.push_bacl(*in_iter++);</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">甚至可以这样写:</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">vetor<int> ivec(in_iter,eof); 用迭代器范围初始化容器。</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">示例:</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main(){
<span style="white-space:pre">	</span>cout << "Enter numbers " << endl;
<span style="white-space:pre">	</span>istream_iterator<int> is(cin);
<span style="white-space:pre">	</span>istream_iterator<int> eof;
<span style="white-space:pre">	</span>ostream_iterator<int> out(cout, " ");
<span style="white-space:pre">	</span>vector<int> ivec(is, eof);
<span style="white-space:pre">	</span>cout << "Output : ";
<span style="white-space:pre">	</span>copy(ivec.begin(), ivec.end(), out);
<span style="white-space:pre">	</span>cout << endl;
<span style="white-space:pre">	</span>system("pause");
<span style="white-space:pre">	</span>return 0;
}</span></span>
使用算法操纵流迭代器:
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <numeric>
using namespace std;
int main(){
	cout << "Enter numbers " << endl;
	istream_iterator<int> is(cin);
	istream_iterator<int> eof;
	cout << accumulate(is, eof, 0);
	system("pause");
	return 0;
}</span></span>
懒惰求值:当一个istream_iterator迭代器和流绑定的时候,不一定是立即从流中读取数据,程序会保证当你解引用的时候,确保数据已经读取成功。
ostream_iterator的操作:

首先明确一点,不像istream_iterator,这个不存在类似尾后迭代器的东西,即定义的时候就必须绑定对象。

此迭代器接受一个可选的参数,此参数必须是C风格字符串,即一定要以空字符结尾。具体的功能体会一下就明白了。

用ostream_iterator进行打印是最爽不过的了。

<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">ostrem_iterator<int> out(cout," ");
for(auto x:vec)
  *out++=e;</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">此处的赋值操作就是把e的值写到cout里,然后就可以输出了。</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">对out的自增自减以及解引用无任何影响,所以可以写成:</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">for(auto x:vec)</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">  out=e;</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">此处的效果和上面完全等价。</span></span>


4.3 反向迭代器:

注意++ 和--的意思也颠倒了。处理forward_list外都支持反向迭代器。

当调用sort排序的时候,顺序也颠倒了,正常是从小到大,现在是从大到小。

反向迭代器的base函数:

<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <string>
using namespace std;
int main(){
	string line = "first,word,last";
	//打印第一个单词。使用find.
	auto iter=find(line.begin(), line.end(), ',');
	cout << string(line.begin(), iter);
	//打印最后一个单词。
	cout << endl;
	auto back_iter =find(line.rbegin(), line.rend(), ',');
	cout << string(line.rbegin(), back_iter); //倒着打印了,如何解决?
	cout << endl;
	auto iter2 = back_iter.base();
	cout << string(iter2, line.cend());
	system("pause");
	return 0;
}</span></span>
<span style="font-size:18px;color:#330099;"><span style="font-size:18px;">自行测试可知。</span></span>

5.泛型算法结构:

任何算法的最基本特性是它要求其迭代器提供哪些操作。

5.1五类迭代器:

<span style="font-size:18px;"><span style="font-size:18px;">1.inpur iterator. 典型的是istream_iteraot;
2.output iterator.典型的是ostream_iterator;
3forward iterator,典型的是 forward_list的。
4.双向迭代器.典型的太多了,除了上面那个。
5.随机访问迭代器.随机访问相关的,也就vector,string,arrat,deque.</span></span>


5.2算法形参模式:

1.接受单个目前迭代器的算法:

<span style="font-size:18px;"><span style="font-size:18px;">alg(beg,end,dest,other_args);</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">蕴含一个编程假定。目的位置的大小至少要与输入范围一样大。</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">如果dest是插入迭代器或者是流迭代器,那么大小就不限制了。</span></span>


5.3命名规范:

1.使用重载形式传递谓词:

<span style="font-size:18px;"><span style="font-size:18px;">unique(beg,end)
unique(beg,end,comp);//comp是一个传递进去的函数。</span></span>
2._if版本:
<span style="font-size:18px;"><span style="font-size:18px;">finf(beg,end,val);
find_if(beg,end,pred);
</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">pred是谓词。</span></span>
3.区分拷贝版本和不拷贝版本。
<span style="font-size:18px;"><span style="font-size:18px;">replace(beg,end,old,new);
replac_copy(beg,end,back_inserter,old,new);</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">甚至还有replace_copy_if(beg,end,bac_inserter,old,new,pred);</span></span>

6.特定的容器算法:

属于容器的成员函数了,考虑到list和forward_list的特性之后,容器单独定义了一些操作。

<span style="font-size:18px;"><span style="font-size:18px;">merge/remove/reverse/sort/unque/splice</span></span>
<span style="font-size:18px;"><span style="font-size:18px;">具体的内容可以查资料。</span></span>

7.习题解答:

10.1

<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main(){
	cout << "Enter numbers or Enter Ctrl+d to stop " << endl;
	istream_iterator<int> in(cin), eof;
	vector<int> ivec(in, eof);//使用流迭代器进行初始化。
	auto x=count(ivec.cbegin(), ivec.cend(), 10);//统计10出现的次数。
	cout << 10 << " occurs " << x << ((x > 1) ? " times " : " time ");
	system("pause");
	return 0;
}</span>

10.2

<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
using namespace std;
int main(){
	cout << "Enter numbers or Enter Ctrl+d to stop " << endl;
	istream_iterator<string> in(cin), eof;
	list<string> lst(in, eof);//使用流迭代器进行初始化。
	auto x=count(lst.cbegin(),lst.cend(),"hello");//统计10出现的次数。
	cout << "The string of hello "<< " occurs " << x << ((x > 1) ? " times " : " time ");
	system("pause");
	return 0;
}</span>
10.3
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
int main(){
	cout << "Enter numbers or Enter Ctrl+d to stop " << endl;
	istream_iterator<string> in(cin), eof;
	cout << accumulate(in, eof, string());  //注意此算法定义在numeric中。
	cout << endl;
	vector<int> ivec{ 1, 2, 3, 4, 5, 6 };
	cout << "The sum is " << accumulate(ivec.cbegin(), ivec.cend(), 0);
	system("pause");
	return 0;
}</span>
10.4
<span style="font-size:18px;">因为第三个参数是0,而字面值0是int型的,但是元素的类型是double.不匹配。</span>
10.5
<span style="font-size:18px;">也可以进行比较啊。
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
int main(){
	list<const char*> list1 = {"world", "hello"};
	list<const char*> list2 = { "world","hello"};
	auto x=equal(list1.cbegin(), list1.cend(), list2.cbegin());
	cout << x << endl;
	system("pause");
	return 0;
}</span>
10.6
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
int main(){
	vector<int> ivec;
	fill_n(back_inserter(ivec), 10, 0);
	ostream_iterator<int> out(cout, " ");
	cout << "Print all the elements : ";
	copy(ivec.begin(), ivec.end(), out);
	cout << endl;
	system("pause");
	return 0;
}</span>
10.7
<span style="font-size:18px;">有。修改:
while (cin >> i)
		lst.push_back(i);
	copy(lst.begin(), lst.end(), back_inserter(ivec));
有。修改:
vector<int> ivec;
	ivec.resize(10);
	fill_n(ivec.begin(), 10, 0);</span>
10.8
<span style="font-size:18px;">算法只是操纵迭代器,不会改变容器大小
是迭代器执行了容器的操作导致大小改变。</span>
10.9
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
void elimDups(vector<string>& word){
    cout << "For the first,Print all the elements :";
    for (auto x : word)
        cout << x << " ";
    cout << endl;
    sort(word.begin(), word.end());
    cout << "After sorting ,print all the elements : ";
    for (auto x : word)
        cout << x << " ";
    cout << endl;
    auto tmp = unique(word.begin(), word.end());
    cout << "After calling unique function ,print all the elements : ";
    for (auto x : word)
        cout << x << " ";
    cout << endl;
    cout << "Now ,the size of the container is " << word.size() << endl;
    word.erase(tmp, word.end());
    cout << "After erasing ,print all the elements :";
    for (auto x : word)
        cout << x << " ";
    cout << endl;
    cout << "Now ,the size of the container is " << word.size() << endl;
    //上面的两次大小一样嘛?unique 不删除元素。
}
int main(){
    cout << "Enter strings " << endl;
    istream_iterator<string> in(cin), eof;
    vector<string> svec(in,eof);
    elimDups(svec);
    system("pause");
    return 0;
}
</span>
10.10
<span style="font-size:18px;">算法只是操纵迭代器,而迭代器只是指向元素(个别迭代器除外),怎么会改变容器大小。
改变大小无非就是删除增加元素,那么肯定要需要调用者,但是传递进来的只是迭代器,所以肯定没法改变大小。</span>
10.11
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
bool is_shorter(const string& s1, const string& s2){
	return s1.size() < s2.size();
}
void elimDups(vector<string>& word){
	cout << "For the first,Print all the elements :";
	for (auto x : word)
		cout << x << " ";
	cout << endl;
	stable_sort(word.begin(), word.end(),is_shorter);
	cout << "After sorting ,print all the elements : ";
	for (auto x : word)
		cout << x << " ";
	cout << endl;
	auto tmp = unique(word.begin(), word.end());
	cout << "After calling unique function ,print all the elements : ";
	for (auto x : word)
		cout << x << " ";
	cout << endl;
	cout << "Now ,the size of the container is " << word.size() << endl;
	word.erase(tmp, word.end());
	cout << "After erasing ,print all the elements :";
	for (auto x : word)
		cout << x << " ";
	cout << endl;
	cout << "Now ,the size of the container is " << word.size() << endl;
	//上面的两次大小一样嘛?unique 不删除元素。
}
int main(){
	cout << "Enter strings " << endl;
	istream_iterator<string> in(cin), eof;
	vector<string> svec(in,eof);
	stable_sort(svec.begin(),svec.end(), is_shorter);
	for(auto x:svec)
		cout << x << " ";
	//elimDups(svec);
	system("pause");
	return 0;
}</span>
10.12
<span style="font-size:18px;">#include<iostream>
#include <string>
#include<vector>
#include <algorithm>
using namespace std;
class Sales_data{
public:
	string isbn;
	friend istream& operator>>(istream& is, Sales_data& p){
		is >> p.isbn;
		return is;
	}
	friend ostream& operator<<(ostream& os, const Sales_data& p){
		os << p.isbn;
		return os;
	}
};
bool compareIsbn(const Sales_data& s1, const Sales_data& s2){
	return s1.isbn < s2.isbn;
}
int main(){
	vector<Sales_data> Sales_data_vector;
	Sales_data temp;
	while (cin >> temp)
		Sales_data_vector.push_back(temp);
	sort(Sales_data_vector.begin(), Sales_data_vector.end(),compareIsbn);
	for (auto x : Sales_data_vector)
		cout << x << endl;
	cout << endl;
	system("pause");
	return 0;
}</span>
10.13
<span style="font-size:18px;">#include<iostream>
#include <string>
#include<vector>
#include <algorithm>
using namespace std;
bool more_than_five(const string& para){
	return ((para.size() > 5) ? true : false);
}
int main(){
	vector<string> svec;
	string word;
	cout << "Enter strings " << endl;
	while (cin >> word)
		svec.push_back(word);
	cout << "Before partition , print all the elements :"<<endl;
	for (auto x : svec)
		cout << x << endl;
	cout << endl;
	partition(svec.begin(), svec.end(), more_than_five);
	cout << "After partition ,print all the elements :"<<endl;
	for (auto x : svec)
		cout << x << endl;
	cout << endl;
	system("pause");
	return 0;
}</span>
10.14
<span style="font-size:18px;">#include <iostream>
using namespace std;
int main(){
	auto f = [](const int& va1, const int& va2) ->int {
		return va1 + va2;};
	cout << f(2, 3)<<endl;
	system("pause");
	return 0;
}</span>
10.15
<span style="font-size:18px;">#include <iostream>
using namespace std;
int main(){
	int temp = 0;
	cout << "Enter numbers :";
	cin >> temp;
	auto f = [&temp](int var){return temp + var; };
	cout << f(2)<<endl;
	system("pause");
	return 0;
}</span>
10.16
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
bool is_shorter(const string& s1, const string& s2){
    return s1.size() < s2.size();
}
void elimDups(vector<string>& word){
    sort(word.begin(), word.end(), is_shorter);
    auto tmp = unique(word.begin(), word.end());
    word.erase(tmp, word.end());
}
void biggies(vector < string>& words, vector<string>::size_type sz){
    elimDups(words);
    stable_sort(words.begin(), words.end(), [](const string& p1, const string    & p2){
        return p1.size() < p2.size(); });
        auto temp = find_if(words.begin(), words.end(), [=](const string p1){
            return p1.size()>sz; });
            auto count = words.end() - temp;
            for_each(temp, words.end(), [](const string& p){cout << p << " "; });
            cout << endl;
}
int main(){
    cout << "Enter strings " << endl;
    istream_iterator<string> in(cin), eof;
    vector<string> svec(in, eof);
    biggies(svec, 5);
    system("pause");
    return 0;
}
</span>
10.17
<span style="font-size:18px;">#include<iostream>
#include <string>
#include<vector>
#include <algorithm>
using namespace std;
class Sales_data{
public:
	string isbn;
	friend istream& operator>>(istream& is, Sales_data& p){
		is >> p.isbn;
		return is;
	}
	friend ostream& operator<<(ostream& os, const Sales_data& p){
		os << p.isbn;
		return os;
	}
};
bool compareIsbn(const Sales_data& s1, const Sales_data& s2){
	return s1.isbn < s2.isbn;
}
int main(){
	vector<Sales_data> Sales_data_vector;
	Sales_data temp;
	while (cin >> temp)
		Sales_data_vector.push_back(temp);
	sort(Sales_data_vector.begin(), Sales_data_vector.end(), [](const Sales_data& p1, const Sales_data& p2){
		return p1.isbn < p2.isbn; });
		for (auto x : Sales_data_vector)
			cout << x << endl;
		cout << endl;
		system("pause");
		return 0;
}</span>
10.18
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
bool is_shorter(const string& s1, const string& s2){
	return s1.size() < s2.size();
}
void elimDups(vector<string>& word){
	sort(word.begin(), word.end(), is_shorter);
	auto tmp = unique(word.begin(), word.end());
	word.erase(tmp, word.end());
}
void biggies(vector < string>& words, vector<string>::size_type sz){
	elimDups(words);
	stable_sort(words.begin(), words.end(), [](const string& p1, const string	& p2){
		return p1.size() < p2.size(); });
		auto temp = partition(words.begin(), words.end(), [=](const string p1){
			return p1.size()<=sz; });
			auto count = words.end() - temp;
			for_each(temp, words.end(), [](const string& p){cout << p << " "; });
			cout << endl;
}
int main(){
	cout << "Enter strings " << endl;
	istream_iterator<string> in(cin), eof;
	vector<string> svec(in, eof);
	biggies(svec, 5);
	system("pause");
	return 0;
}</span>
10.19
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
using namespace std;
bool is_shorter(const string& s1, const string& s2){
	return s1.size() < s2.size();
}
void elimDups(vector<string>& word){
	sort(word.begin(), word.end(), is_shorter);
	auto tmp = unique(word.begin(), word.end());
	word.erase(tmp, word.end());
}
void biggies(vector < string>& words, vector<string>::size_type sz){
	elimDups(words);
	stable_sort(words.begin(), words.end(), [](const string& p1, const string	& p2){
		return p1.size() < p2.size(); });
		auto temp = stable_partition(words.begin(), words.end(), [=](const string p1){
			return p1.size()<=sz; });
			auto count = words.end() - temp;
			for_each(temp, words.end(), [](const string& p){cout << p << " "; });
			cout << endl;
}
int main(){
	cout << "Enter strings " << endl;
	istream_iterator<string> in(cin), eof;
	vector<string> svec(in, eof);
	biggies(svec, 5);
	system("pause");
	return 0;
}</span>
10.20
<span style="font-size:18px;">#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
	cout << "Enter strings" << endl;
	istream_iterator<string> is(cin), eof;
	vector<string> svec(is, eof);
	//统计次数。
	auto number = count_if(svec.begin(), svec.end(), [](const string& p){return p.size()<5; });
	cout << "The length of string less than 5 occurs " << number << (number > 1 ? " times " : " time ")<<endl;
	system("pause");
	return 0;
}</span>
10.21
<span style="font-size:18px;">#include <iostream>
using namespace std;
int main(){
	int val = 0;
	cout << "Enter  a number :";
	cin >> val;
	auto f = [&]()->bool{
		while (val != 0)
			--val;
		if (val == 0)
			return true;
		else
			return false; };
	if (f())
		cout << "Successful" << endl;
	else
		cout << "Failed" << endl;
	system("pause");
	return 0;
}</span>
10.22
<span style="font-size:18px;">#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
bool check_size(const string& p,string::size_type sz){
	return p.size()<=sz; 
}
int main(){
cout << "Enter strings" << endl;
istream_iterator<string> is(cin), eof;
vector<string> svec(is, eof);
//统计次数。
auto number = count_if(svec.begin(), svec.end(),bind(check_size,_1,6));
cout << "The length of string less than 7 occurs " << number << (number > 1 ? " times " : " time ")<<endl;
system("pause");
return 0;
}</span>
10.23
<span style="font-size:18px;">bind 现在形参个数?</span>


10.24
<span style="font-size:18px;">#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
using namespace std::placeholders;
using namespace std;
bool check_size(const string& p, string::size_type sz){
	return p.size() > sz;
}
int main(){
	cout << "Enter strings " << endl;
	istream_iterator<string> is(cin), eof;
	vector<string> svec(is, eof);
	auto iter = find_if(svec.begin(), svec.end(), bind(check_size, _1, 6));
	cout << *iter << endl;
	system("pause");
	return 0;
}</span>
10.25
<span style="font-size:18px;">#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
#include <list>
#include <numeric>
#include <functional>
using namespace std;
using namespace std::placeholders;
bool is_shorter(const string& s1, const string& s2){
	return s1.size() < s2.size();
}
bool check_size(const string& p, string::size_type sz){
	return p.size() < sz;
}
void elimDups(vector<string>& word){
	sort(word.begin(), word.end(), is_shorter);
	auto tmp = unique(word.begin(), word.end());
	word.erase(tmp, word.end());
}
void biggies(vector < string>& words, vector<string>::size_type sz){
	elimDups(words);
	stable_sort(words.begin(), words.end(), [](const string& p1, const string	& p2){
		return p1.size() < p2.size(); });
		auto temp = partition(words.begin(), words.end(), bind(check_size, _1, sz));
		auto count = words.end() - temp;
		for_each(temp, words.end(), [](const string& p){cout << p << " "; });
		cout << endl;
}
int main(){
	cout << "Enter strings " << endl;
	istream_iterator<string> in(cin), eof;
	vector<string> svec(in, eof);
	biggies(svec, 5);
	system("pause");
	return 0;
}</span>

10.26

三种迭代器:
1.back_inserter;
2.front_inserter;
3.inserter;
主要区别是插入的位置不同。
10.27

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
	cout << "Enter strings ." << endl;
	istream_iterator<string> in(cin), eof;
	ostream_iterator<string> out(cout, " ");
	vector<string> svec(in, eof);
	cout << "Print all the elements in the vector :";
	copy(svec.begin(), svec.end(), out);
	cout << endl;
	sort(svec.begin(), svec.end());
	list<string> lst;
	unique_copy(svec.begin(), svec.end(), back_inserter(lst));//必须是已经排序的容器序列。
	cout << "Print all the elements in the list :";
	copy(lst.begin(), lst.end(), out);
	cout << endl;
	system("pause");
	return 0;
}
10.28

#include <vector>
#include <iostream>
#include <iterator>
#include <list>
#include <algorithm>
using namespace std;
int main(){
	vector<int> ivec1, ivec3, ivec{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	list<int> lst2;
	ostream_iterator<int> out(cout, " ");
	copy(ivec.begin(), ivec.end(), back_inserter(ivec1));//输出序列应该是1-9.
	cout << "Print all the elements in the container of ivec1 :";
	copy(ivec1.begin(), ivec1.end(), out);
	cout << endl;
	copy(ivec.begin(), ivec.end(), front_inserter(lst2));//输出序列应该是9-1;
	cout << "Print all the elements in the container of lst2 :";
	copy(lst2.begin(), lst2.end(), out);
	cout << endl;
	copy(ivec.begin(), ivec.end(), inserter(ivec3,ivec3.begin()));//输出序列应该是1-9.
	cout << "Print all the elements in the container of ivec3 :";
	copy(ivec1.begin(), ivec1.end(), out);
	cout << endl;
	system("pause");
	return 0;
}
11.29

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
	ofstream out("test.txt");
	out << "hello world . This is a sample " << endl;
	out.close();
	ifstream in("test.txt");
	istream_iterator<string> inflie(in), eof;
	vector<string> svec(inflie, eof);
	cout << "Print all the elements :";
	ostream_iterator<string> output(cout, " ");
	copy(svec.begin(), svec.end(), output);
	cout << endl;
	system("pause");
	return 0;
}
11.30

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
	cout << "Enter numbers : ";
	istream_iterator<int> in(cin), eof;
	vector<int> ivec(in, eof);
	cout << endl << "Call the sort function " ;
	sort(ivec.begin(),ivec.end());
	cout << "Output :";
	ostream_iterator<int> out(cout, " ");
	copy(ivec.begin(), ivec.end(), out);
	cout << endl;
	system("pause");
	return 0;
}
11.31

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
	cout << "Enter numbers : ";
	istream_iterator<int> in(cin), eof;
	vector<int> ivec(in, eof);
	cout << endl << "Call the sort function " ;
	sort(ivec.begin(),ivec.end());
	vector<int> ivec2;
	unique_copy(ivec.begin(), ivec.end(), back_inserter(ivec2));
	cout << "Output :";
	ostream_iterator<int> out(cout, " ");
	copy(ivec2.begin(), ivec2.end(), out);
	cout << endl;
	system("pause");
	return 0;
}
11.32

#include <iostream>
#include <fstream>
#include <iterator>
#include <algorithm>
using namespace std;
void func(ifstream& in, ofstream& out1, ofstream& out2){
	istream_iterator<int> infile(in), eof;
	istream_iterator<int> infile1(in), eof1;
	//将奇数写到第一个文件。
	ostream_iterator<int> outfile(out1, " ");
	ostream_iterator<int> outfile1(out2, "\n");
	copy_if(infile, eof,outfile, [](int val){return ((val % 2 != 0) ? true : false); });
	copy_if(infile1, eof1,outfile1, [](int val1){return ((val1 % 2 != 0) ? false : true); });
}
int main(){
	ofstream out("test.txt");
	out << 1 << 2 << 3 << 5 << endl;
	out << 22 << endl;
	out << 33 << endl;
	out.close();
	ifstream in("test.txt");
	ofstream out1("output_1.txt"), out2("output_2.txt");
	func(in, out1, out2);
	system("pause");
	return 0;
}
11.33

略。

11.34

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
	cout << "Enter numbers : ";
	istream_iterator<int> in(cin), eof;
	vector<int> ivec(in, eof);
	auto iter = ivec.rbegin();
	while (iter != ivec.rend())
		cout << *iter++<<" ";
	cout << endl;
	system("pause");
	return 0;
}
11.35

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
	cout << "Enter numbers : ";
	istream_iterator<int> in(cin), eof;
	ostream_iterator<int> out(cout, " ");
	vector<int> ivec(in, eof);
	copy(ivec.begin(), ivec.end(), out);
	cout << endl;
	system("pause");
	return 0;
}
11.36

#include <iostream>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
int main(){
	cout << "Enter numbers : ";
	istream_iterator<int> in(cin), eof;
	ostream_iterator<int> out(cout, " ");
	list<int> lst(in, eof);
	//正常的find算法是查找第一个相等的元素。
	auto end = lst.rbegin(), beg = lst.rend();
	auto iter = find(end, beg, 0);
	if (iter == lst.rend())
		cout << "Not be present !" << endl;
	else
		cout << "Be present !" << endl;
	system("pause");
	return 0;
}
11.37

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <list>
using namespace std;
int main(){
	vector<int> ivec{ 1, 2, 13, 14, 15, 16, 17, 8, 9, 10 };
	auto iter1 = ivec.rbegin() + 3;
	auto iter2 = ivec.rend() - 2;
	list<int> lst;
	copy(iter1, iter2, back_inserter(lst));
	ostream_iterator<int> out(cout, " ");
	copy(lst.begin(), lst.end(), out);
	cout << endl;
	system("pause");
	return 0;
}
11.38

1.输入迭代器。
2.输入迭代器。
3.前向迭代器。
4.双向迭代器。
5.随机访问迭代器。
11.39

list的迭代器是双向迭代器。
vector是随机访问迭代器。
11.40

因为copy涉及到写元素,所以要有输出迭代器。
reverse双向迭代器。
unique 要求双向迭代器。
11.41

1.范围内的用新值代替查找到的旧值。
2.范围使谓词为真的元素用新值替代。
3.把替换过的拷贝到新的容器。
4.把使谓词为真用新值替换,然后拷贝到新的容器。
11.42

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <list>
#include <string>
using namespace std;
void elimDups(list<string>& lst){
	lst.sort();
	lst.unique();//不需要调用erase函数,因为list的unique是会删除的。
}
int main(){
	cout << "Enter strings :" << endl;
	istream_iterator<string> in(cin), eof;
	list<string> lst(in,eof);
	elimDups(lst);
	ostream_iterator<string> out(cout, " ");
	copy(lst.begin(), lst.end(), out);
	cout << endl;
	system("pause");
	return 0;
}


8.后记:

今天去同学聚会了,看见了以前的老师,很开心,好开心。

End

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: