C++Primer学习笔记(9)

这篇文章的内容是泛型算法。前面的一章讲的是各种各样的方法,那些方法有些是针对容器的,有些是针对迭代器的。本章主要介绍的是针对迭代器的,这些方法死记硬背总不太好吧,那么这章将会比较深刻地分析其背后规律帮助我们更好地理解记忆那些方法。

然后,学习本章感觉得结合设计模式的思想来理解会更有意思,要不然有点枯燥

C++Primer学习笔记(9)_第1张图片

要开始进阶了。泛型 --一个能提高程序复用度的利器。

这段话可以理解为一个通用的算法。

一、概述

C++Primer学习笔记(9)_第2张图片C++Primer学习笔记(9)_第3张图片

以上就是在讲find函数如何使用的。

 1)算法如何工作

C++Primer学习笔记(9)_第4张图片

2) 迭代器算法不依赖于容器

C++Primer学习笔记(9)_第5张图片

即对不同的迭代器find函数都可以使用。

3)算法依赖于元素类型的操作

 这些概述大致是在将泛型算法具有哪些特点。

C++Primer学习笔记(9)_第6张图片C++Primer学习笔记(9)_第7张图片

第一句话很重要:泛型算法运行于迭代器之上,执行迭代器的操作。 

二、初识泛型算法

C++Primer学习笔记(9)_第8张图片

1.只读算法

C++Primer学习笔记(9)_第9张图片

 1)算法和元素类型

C++Primer学习笔记(9)_第10张图片C++Primer学习笔记(9)_第11张图片

 泛型算法对容器是通用的,但是需要考虑容器中的元素类型。 通过accumulate方法引出这一规律。

2)操作两个序列的算法

 通过举例equal方法来引出如何用迭代器操作两个不同的容器。

2.写容器元素的算法

C++Primer学习笔记(9)_第12张图片C++Primer学习笔记(9)_第13张图片

 1)算法不检查写操作

C++Primer学习笔记(9)_第14张图片C++Primer学习笔记(9)_第15张图片

 2)back_inserter

C++Primer学习笔记(9)_第16张图片

 这种迭代器可以拿来批量化为容器添加元素。

 3)拷贝算法

C++Primer学习笔记(9)_第17张图片C++Primer学习笔记(9)_第18张图片

 copy方法的使用方式与前面介绍的equal方法类似。

C++Primer学习笔记(9)_第19张图片

 个人感觉这些方法都不太实用,真的遇到了还不如自己写一个来的快。

 3.重排容器元素的算法

C++Primer学习笔记(9)_第20张图片

这是引入,后面的几个小内容都会以这个举例。 

 1)消除重复单词

C++Primer学习笔记(9)_第21张图片

2)使用unique

C++Primer学习笔记(9)_第22张图片

注意最后一句话:标准库算法对迭代器而不是容器进行操作

 3)使用容器操作删除元素

C++Primer学习笔记(9)_第23张图片

 再次注意!:迭代器是无法真正删除或添加元素的,要添加和删除必须是容器操作

三、定制操作

C++Primer学习笔记(9)_第24张图片

还是不太明白为什么讲泛型算法讲着讲着就引入lambda表达式了,这个内容引入设置感觉不太友好。

1.向算法传递函数

首先要清楚什么是谓词,本书没介绍什么是谓词就给出这个概念,对新人也太不友好了吧。

谓词函数就是一个返回布尔值的函数。可参考:

C++谓词函数(无师自通)

C++ - 算法(algorithm) 的 谓词(predicate) 详解_Mystra-CSDN博客_c++谓词

 1)谓词

C++Primer学习笔记(9)_第25张图片C++Primer学习笔记(9)_第26张图片

举例说明:

bool special(const int& a, const int& b) {
	return a > b;
}
void Learn9GenericAlgorithm::specialOperation()
{
	vector vec{1, 9, 3, 7, 2, 9, 8, 7, 6, 6, 5};
	sort(vec.begin(), vec.end(), special);//greater()
	for (const int& v : vec)cout << v << "   ";//从小到大输出
}

2)排序算法

C++Primer学习笔记(9)_第27张图片

 2.lambda表达式

C++Primer学习笔记(9)_第28张图片C++Primer学习笔记(9)_第29张图片

 这一块跳跃有点快,有点难理解,可以建议先看后面的例子再返回来理解这一大段话。

1)介绍lambda

C++Primer学习笔记(9)_第30张图片C++Primer学习笔记(9)_第31张图片

 关于lambda的使用可参考:C++之Lambda表达式 - 季末的天堂 - 博客园

 2)向lambda传递参数

C++Primer学习笔记(9)_第32张图片

 3)使用捕获列表

C++Primer学习笔记(9)_第33张图片

这一块理解起来相对简单。

4)调用find_if

C++Primer学习笔记(9)_第34张图片

 理解到这一步再返回去看前面介绍的那一大段话就理解多了。

 5)for_each算法

C++Primer学习笔记(9)_第35张图片

 for_each方法可以方便简洁地对容器的遍历。

 7)完整的biggies函数

C++Primer学习笔记(9)_第36张图片

 即将上面讲的都串起来了。

3.lambda捕获与返回

C++Primer学习笔记(9)_第37张图片

 1)值捕获

C++Primer学习笔记(9)_第38张图片

类似函数的值传递 

2)引用捕获

C++Primer学习笔记(9)_第39张图片C++Primer学习笔记(9)_第40张图片

与函数的引用参数传递类似。不能返回局部变量的引用值得注意。

 注意事项:

C++Primer学习笔记(9)_第41张图片

 3)隐式捕获

C++Primer学习笔记(9)_第42张图片C++Primer学习笔记(9)_第43张图片

上面讲了那么多不如直接看下面这个表理解的快。

C++Primer学习笔记(9)_第44张图片

 4)可变lambda

C++Primer学习笔记(9)_第45张图片C++Primer学习笔记(9)_第46张图片

fcn3()和fcn4()这两个函数看懂了大致就知道什么意思了。即非引用捕获要在lambda函数体内改变捕获值那么要加上mutable。

举个例子:

	int lam = 2;
	auto r = [&lam] {return ++lam; };
	auto r1 = [lam]()mutable {return ++lam; };//()mutable一个都不能少写
	lam = 0;
	cout << r() <

 5)指定lambda返回类型

 这里其实是要举个例告诉我们怎么使用尾置返回类型。C++Primer学习笔记(9)_第47张图片

以上情况编译器可以自动推断返回类型,因此可以省略尾置返回类型。

C++Primer学习笔记(9)_第48张图片

 而这个例子我们就需要使用尾置返回类型了,否则编译器无法推断返回类型。

4.参数绑定

C++Primer学习笔记(9)_第49张图片

1)标准库bind函数

 有点类似与lambda表达式的一个替代方案。

 2)绑定check_size的sz参数

以下内容即举例说明bind函数怎么用

C++Primer学习笔记(9)_第50张图片

 3)使用placeholder名字

 感觉讲了一堆废话,即使用占位符要引入命名空间placeholder

 4)bind的参数

C++Primer学习笔记(9)_第51张图片

5)使用bind重排参数顺序

C++Primer学习笔记(9)_第52张图片

是对bind函数的一个灵活运用。 

6)绑定引用参数

C++Primer学习笔记(9)_第53张图片C++Primer学习笔记(9)_第54张图片 

四、再探迭代器

C++Primer学习笔记(9)_第55张图片C++Primer学习笔记(9)_第56张图片

接下来要介绍这几种迭代器了。

1.插入迭代器

C++Primer学习笔记(9)_第57张图片

关于插入迭代器可参考:插入迭代器_lusic01的专栏-CSDN博客_插入迭代器 

C++Primer学习笔记(9)_第58张图片C++Primer学习笔记(9)_第59张图片

主要区分上面三个插入迭代器之间的区别。

	list lst = { 1,2,3 }, lst1,lst2;
	auto iter1 = front_inserter(lst1);
	copy(lst.cbegin(), lst.cend(), iter1);
	copy(lst.cbegin(), lst.cend(), back_inserter(lst2));
	for (auto const& l : lst1)cout << l << "  ";//输出321
	for (auto const& l : lst2)cout << l << "  ";//输出123

 2.iostream迭代器

C++Primer学习笔记(9)_第60张图片

1)istream_iterator操作

C++Primer学习笔记(9)_第61张图片C++Primer学习笔记(9)_第62张图片

 讲了那么多不如跑跑代码理解理解:

	istream_iterator int_iter(cin),eof;
	while (int_iter != eof)cout << *(int_iter++) << "   ";

 2)使用算法操作流迭代器

C++Primer学习笔记(9)_第63张图片

3)istream_iterator允许懒惰求值

C++Primer学习笔记(9)_第64张图片 

4)ostream_iterator操作

C++Primer学习笔记(9)_第65张图片C++Primer学习笔记(9)_第66张图片

讲的那么多不如自己动手写一写:

	ostream_iterator out_iter(cout, "  ");
	vector vec{ 1,2,3,4,5 };
	for (int v : vec)out_iter = v;
	cout << endl;
	copy(vec.begin(), vec.end(), out_iter);
	cout << endl;

 输出:

 5)使用流迭代器处理类类型

C++Primer学习笔记(9)_第67张图片

3.反向迭代器

 C++Primer学习笔记(9)_第68张图片C++Primer学习笔记(9)_第69张图片

 反向迭代器没啥好说的,就是顺序是反的迭代器。

 1)反向迭代器需要递减运算符

C++Primer学习笔记(9)_第70张图片

2)反向迭代器与其他迭代器之间的关系

C++Primer学习笔记(9)_第71张图片C++Primer学习笔记(9)_第72张图片C++Primer学习笔记(9)_第73张图片

五、泛型算法结构

C++Primer学习笔记(9)_第74张图片

1.五类迭代器

C++Primer学习笔记(9)_第75张图片

 1)迭代器类别什么

为甚有一堆迭代器类别,主要是为了使程序的功能进一步解耦以及与细化明确。

C++Primer学习笔记(9)_第76张图片C++Primer学习笔记(9)_第77张图片C++Primer学习笔记(9)_第78张图片

可以把迭代器当成指针一样。注意还是有很多迭代器不是随机访问迭代器的,比如set和list等等。

	vector vec{ 1,2,3 };
	auto iter = vec.begin();
	auto* p = &vec.front();
	cout << iter[1] << endl << *(iter+1)<

 2.算法的形参模式

C++Primer学习笔记(9)_第79张图片

对迭代器算法常见的模式进行总结。

1)接受单个目标迭代器的方法

C++Primer学习笔记(9)_第80张图片

 2)接受第二个输入序列的算法

这个没啥好讲的,就是说这种格式是把一块东西搞到另一块地方。

 3.算法命名规范

1) 使用重载形式传递一个谓词的方法

C++Primer学习笔记(9)_第81张图片

那么谓词重载又该怎么定义函数呢? 这或许得去看看STL的源码了。 

2)_if版本的算法

C++Primer学习笔记(9)_第82张图片

3)区分拷贝元素的版本和不拷贝元素的版本

C++Primer学习笔记(9)_第83张图片

 记住拷贝元素的版本加了个copy即可。

六、特定容器算法

1.list与forward_list

C++Primer学习笔记(9)_第84张图片C++Primer学习笔记(9)_第85张图片

 list与forward_list的相关方法经常与其他容器不一样。

 1)splice成员

 2)链表特有的操作会改变容器

你可能感兴趣的:(编程语言学习笔记C++,c++,经验分享)