C++、STL标准模板库和泛型编程 ——迭代器、 算法、仿函数(侯捷)

news2024/10/5 22:18:24

C++、STL标准模板库和泛型编程 ——迭代器、 算法、仿函数 (侯捷)

  • 迭代器
    • iterator_category
  • 算法
    • accumulate
    • for_each
    • replace
    • count
    • find
    • sort
    • binary_search
  • 仿函数 functors(六大部件中最简单的一种!)

使用一个东西,却不明白它的道理,不高明!—— 林语堂

阶段学习
使用C++标准库
认识C++标准库(胸中自有丘壑!)
良好使用C++标准库
扩充C++标准库

所谓 Generic ProgrammingGP,泛型编程),就是使用 template (模板)为主要工具来编写程序。

  • GP 是将 datasmethods 分开来;

    • ContainersAlgorithms可各自闭门造车﹐其间以Iterator连通即可·
    • Algorithms通过Iterators确定操作范围﹐也通过Iterators取用 Container元素。
  • OOP(Object-Oriented Programming),企图将 datasmethods 关联在一起。

C++标准模板库Standard Template 最重要的六大部件(Components):容器算法仿函数迭代器适配器分配器

  • 容器(Containers)是class template
  • 算法(Algorithms)是function template其内最终涉及元素本身的操作,无非就是比大小!)
  • 迭代器(Iterators)是class template
  • 仿函数(Functors)是class template
  • 适配器(Adapters)是class template
  • 分配器(Allocators)是class template

关系图:
在这里插入图片描述

迭代器

前面说到迭代器中必须要有5种关联类型:pointerreferenceiterator_category(迭代器类型,比如说随机存取)、value_type(值存放类型)、difference_type(容器两个元素之间的距离类型)。

iterator_category

也有五种迭代器类型:随机存取迭代器arrayvectordeque)、双向迭代器list红黑树容器)、单向迭代器forward_listhash类容器)、输入迭代器istream迭代器),输出迭代器ostream迭代器)。

在这里插入图片描述
既然是tag,为什么要用有继承关系的class来实现呢?

  • 方便迭代器类型作为参数进行传递,如果是整数的是不方便的;还有一个原因,有些算法的实现没有实现特定类型的迭代器类别,就可以用继承关系去找父迭代器类别。

在这里插入图片描述
iterator_category对算法的影响

以这个distance函数为例,会根据迭代器的类别来调用不同的具体实现函数,

  • 一个是只包含一个减法操作的语句,
  • 一个是包含一个while循环的语句,可想而知,当真实距离很大时,有while循环的具体实现函数效率会非常低下。

使用萃取机iterator_traits,虽然只有两种,但是这几种类型都是继承关系is a 父类input_iterator_tag,如果没有重载,最终都会落到input_iterator_tag

在这里插入图片描述

看一个特别能体现C++注重效率的体现:
copy实现,到最终的实现细节,经过了很多判断,这些判断是为了找到最高效率的实现,就是判断迭代器的分类。

在这里插入图片描述
在这里插入图片描述

算法

Algorithms看不见Containers,对其一无所知;所以,它所需要的一切信息都必须从Iterators取得,而Iterators(由Containers供应)必须能够回答Algorithm的所有提问,才能搭配该Algorithm的所有操作。

template<typename Iterator>
Algorithm(Iterator it1, Iterator it2){
	...
}

template<typename Iterator, typename Cmp>//Cmp为传入的一个准则,比如比大小准则
Algorithm(Iterator it1, Iterator it2, Cmp comp){
	...
}

accumulate

template<class InputInterator, class T>
T accumulate(InputIterator first, InputIterator last, T init){...}

//另外一个版本为:
template<class InputInterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op){...}

上面这个binary_op指明是一个二元操作数的函数,可以是仿函数(实质上是一个类),也可以是函数,只要是能够在该算法的函数体内通过小括号调用就行!!!!

  • 也就是能够这么用:binary_op(a, b);
  • 就算是在算法(函数)里面,也能够使用仿函数,但是传入的是仿函数的对象实例,而如果要传入函数的话,就传函数名就可以了。
int init = 100;
int nums[] = {10,20,30};
accumulate(nums, nums+3, init);//不指定具体怎么操作,默认为加法,输出160
accumulate(nums, nums+3, init, minus<int>()); //这minus时减法的意思,所以输出为40

for_each

  • 对容器区间内的元素做同样的事情。
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f){...}

replace

1、 replace

  • 将容器区间内的元素进行替换,如果元素值等于old_value就把它替换为new_value.
template<class ForwardIterator, class T>
void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value){...}

2、replace_if

  • 在算法中看到 if ,就代表你要给他一个条件。
  • Predicate为一个条件,判断式子(传回),如果符合条件就进行替换
template<class ForwardIterator, class Predicate, class T>
void replace_copy(ForwardIterator first, ForwardIterator last,  Predicate pred, const T& new_value){...}

3、replace_copy

  • 范围内所有等同于old_value的都以new_value放置新的区间中,不符合原值的也放入新的区间
template<class InputIterator, class OutputIterator, class T>
OutputIterator replace_copy(InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value)
{...}

count

容器不带成员函数count():

array, vector, list, forward_list, deque

容器带有成员函数count()红黑树hash容器中有自己的count):

set /multiset
map / multimap
unordered_set / unordered_multiset
unordered_map / unordered_multimap

1、count

  • 区间内有和value相等的元素count + 1
template<class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last, const T& value){...}

2、count_if

  • 区间内有符合pred条件的 count + 1
template<class InputIterator, class Predicate>
typename iterator_traits<InputIterator>::difference_type
count_if(InputIterator first, InputIterator last, Predicate pred){...}

find

容器不带成员函数find():

array, vector, list, forward_list, deque

容器带有成员函数find()红黑树hash容器中有自己的find):

set /multiset
map / multimap
unordered_set / unordered_multiset
unordered_map / unordered_multimap

1、find

  • 循序查找,返回第一个和value相等的迭代器
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value){...}

1、find_if

  • 循序查找,查找符合条件的第一个元素的迭代器
template<class InputIterator, class Predicate>
InputIterator find_if(InputIterator first, InputIterator last, Predicate pred){...}

sort

  • sort要求RandomAccessIterator

容器不带成员函数sort():

array, vector, deque

//已经排序,遍历自然形成sorted状态
set /multiset
map / multimap
unordered_set / unordered_multiset
unordered_map / unordered_multimap

容器带有成员函数sort():下面这两种容器都不能 " "

list, forward_list

sort

  • 默认从小到大排序,也可以指定自己的比较函数,可以是仿函数,可以是函数,仿函数必须传入该仿函数的实例。
sort(InputIterator first, InputIterator last, Function f)

binary_search

  • 一定是在已排序状态下
  • 源码中就是调用lower_bound
template<class ForwardIterator, class T>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value){...}

在这里插入图片描述

lower_bound(ForwardIterator first, ForwardIterator last, T target)
upper_bound(ForwardIterator first, ForwardIterator last, T target)

lower_bound二分查找的一个版本,如果找到对应的值,则返回指向其中第一个元素的迭代器,如果不存在,则返回最适合安插这个target的点的迭代器 ,也就是说它返回迭代器指向第一个不小于target的元素,返回的是不破坏排序得以安插target的第一个适当位置。

仿函数 functors(六大部件中最简单的一种!)

  • 只为算法而服务!
  • class模仿函数,必须要重载小括号()

有三大类,大该至少共有24个仿函数:

  • 算术类+-*/ 等);
  • 逻辑运算类&&|| 等);
  • 相对关系类(返回 bool )。

算术类:(Arithmetic)

template<class T>
struct plus : public binary_function<T, T, T>{
	T operator()(const T& x, const T& y) const{
		return x + y;
	}
};

template<class T>
struct minus : public binary_function<T, T, T>{
	T operator()(const T& x, const T& y) const{
		return x - y;
	}
};

...

逻辑运算类:(Logical)

template<class T>
struct logical_and : public binary_function<T, T, bool>{
	bool operator()(const T& x, const T& y) const{
		return x && y;
	}
};

...

相对关系类:(Relational)

template<class T>
struct equal_to : public binary_function<T, T, bool>{
	bool operator()(const T& x, const T& y) const{
		return x == y;
	}
};

template<class T>
struct less : public binary_function<T, T, bool>{
	bool operator()(const T& x, const T& y) const{
		return x < y;
	}
};

...

使用例子:

//using explicitly default comparison(operator <):
sort(myvec.begin(), myvec.end(), less<int>());

为什么要把它们设计成仿函数呢?

  • 因为要传入算法!要把它们作为参数

上面的列举的几个都继承binary_function,说明有两个操作数,为什么要让仿函数继承这些类呢?

  • 首先,继承他们,不会增加仿函数的内存大小;
  • 其次,继承了他们,会有了first_argument_type等的typedef,后续可以根据这个类型进行一些修改。
  • 以及仿函数(functors)的可适配(adaptable)条件:STL规定每个Adaptable Function都应挑选适当地继承unary_fucntionbinary_function等类,才能融入到STL中,才能回答适配器的问题 (就像Traits机要回答迭代器的问题一样)。

unary_fucntionbinary_function的定义:

//一个操作数(例如 对一个值取反)
template<class Arg, class Result>
struct unary_fucntion{//理论上大小为0,(sizeof为1)
	typedef Arg argument_type;
	typedef Result result_type;
}

//两个操作数
template<class Arg1, class Arg2, class Result>
struct bianry_fucntion{//理论上大小为0,(sizeof为1)
	typedef Arg1 first_argument_type;
	typedef Arg2 second_argument_type;
	typedef Result result_type;
}

注:仅供学习参考,如有不足,欢迎指正!

觉得有帮助的话,点个赞呗(^ - ^)!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/457710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Compiler- volatile关键字

为了直观的感受编译器为程序所做的编译优化&#xff0c;我们通过以下的C程序来进行演示&#xff08;只能体现编译优化的一小部分hh~&#xff09;。 请大家预测一下下面代码的输出结果 #include <iostream>int main(void) {const volatile int local 10;int* ptr (int…

中国人民大学与加拿大女王大学金融硕士国际班——海归学子最强后援

有人脉&#xff0c;成功像坐电梯&#xff1b;没人脉&#xff0c;成功像爬楼梯。这是每一个职场人都有体悟的“潜规则”。对海归同学来说&#xff0c;加入母校校友会是结识优秀人才、迅速拓展本地人脉圈的不二法宝。中国人民大学与加拿大女王大学金融硕士国际班为海归学子提供最…

QMS-云质说质量 - 4 为什么有的质量人不属于质量部?

想管理好质量&#xff0c;首先就要把质量人员放在合适的组织架构中。 对人进行管理&#xff0c;基本原则是&#xff1a;尽量让员工的利益与企业的利益保持同步&#xff0c;虽然无法做到完全重合&#xff0c;但出发点肯定要战略一致。 俗话说“屁股决定脑袋”&#xff0c;因此&a…

【数据结构初阶】第六节.队列的实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、队列的初步认识 二、Java中队列的使用 三、队列的模拟实现 四、力扣刷题演练 4.1 设计循环队列 4.2 用栈实现队列 4.3 最小栈 总结 前言 今天我…

日撸 Java 三百行day36

文章目录 day36 领接表1. 领接表知识点2.结合上图去抽象一个邻接表结点的对象3.广度优先遍历4.深度优先遍历 #说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了github上维护&#xff1a;h…

Vue3+Three.js+antvG2实战项目 智慧城市(三)

前言 在网上找了很久都没有找到使用Three.js开发智慧城市的免费文章或者免费视频,自己花了一点时间做了一个纯前端的智慧城市项目。 技术栈都是最新的:vue3vitetypeScriptThreeantv G2 源码分享 源码 模型,天空图盒子链接分享(不想下载源码可以只用下这个)提取码1234 20230424_…

【iOS】—— KVC再学习

KVC 文章目录 KVCKVC常用的四种方法 key和keyPath的区别用法&#xff1a; 批量存值操作批量赋值操作字典模型相互转化KVC的其他方法 KVC原理探索setValue:forKey: 的原理&#xff08;KVC赋值原理&#xff09;valueForKey:的原理&#xff08;KVC取值原理&#xff09; 注意事项 K…

C++数据结构:手撕AVL树

目录 一. 什么是AVL树 二. AVL树的节点定义 三. AVL树的插入操作 3.1 寻找插入位置 3.2 更新平衡因子 3.3 AVL树的旋转调整 3.4 AVL树插入操作的整体实现 四. AVL树的检验 附录&#xff1a;AVL树的实现完整代码 AVL树定义代码 -- AVLTree.h AVL树检验代码 -- test.…

你了解PostProcessor机制吗?

Spring框架对于后置处理器的最佳实践 PostProcessor译为后置处理器&#xff0c;大多数开发人员都使用过springboot对后置处理器的实例级别实践&#xff0c;也就是BeanPostProcessor接口。其实spring还提供了两种容器级别的实践&#xff1a;BeanDefinitionRegistryPostProcesso…

今天试了试chatgpt

今天试了试chatgpt&#xff0c;真是服了 arcade&#xff1f; Arcade是一个Python游戏开发库&#xff0c;它提供了一系列的工具和函数&#xff0c;可以帮助开发者快速地创建2D游戏。以下是Arcade的一些特点&#xff1a; 简单易用&#xff1a;Arcade提供了简单易用的API&#x…

egg3.0连接egg-mongoose插入一条数据、插入多条数据

插入一条数据 app/router.js use strict;/*** param {Egg.Application} app - egg application*/ module.exports app > {const { router, controller } app;router.get(/, controller.home.index);router.get(/role, controller.role.index);router.post(/role/add, co…

【ChatGPT】如何用十分钟部署一个属于自己的chatgpt网站

&#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#xff1a;Zeeland&#x1f4da; Github主页: Undertone0809 (Zeeland) (github.com)&…

【两个月算法速成】day03-链表

目录 203. 移除链表元素 题目链接 思路 代码 206. 反转链表 题目链接 思路 代码 总结 203. 移除链表元素 题目链接 力扣 思路 如下图所示就是移除链表的过程 但是值得注意的是&#xff0c;移除头节点和其他位置的节点是不一样的&#xff0c;以为头结点前面没有节点。…

每日学术速递4.24

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Collaborative Diffusion for Multi-Modal Face Generation and Editing(CVPR 2023) 标题&#xff1a;多模态人脸生成和编辑的协同扩散 作者&#xff1a;Ziqi Huang, Kelvin C.K. …

Vue3进阶使用详解(node.js、Vue3路由基础项目、axios的使用详细(实现数据分页---前后端分离)、axios加载失败)

Vue3进阶使用详解(node.js、Vue3路由基础项目、axios的使用详细(实现数据分页—前后端分离)、axios加载失败) Vue cli CLI是Commond-Line Interface&#xff0c;翻译为命令界面&#xff0c;又称脚手架。VueCLI是一个官方发布vue.js项目脚手架。使用VueCLI可以快速搭建vue开发…

【IAR工程】STM8S基于ST标准库读取DHT11数据

【IAR工程】STM8S基于ST标准库读取DHT11数据 ✨申明&#xff1a;本文章仅发表在CSDN网站&#xff0c;任何其他网站&#xff0c;未注明来源&#xff0c;见此内容均为盗链和爬取&#xff0c;请多多尊重和支持原创!&#x1f341;对于文中所提供的相关资源链接将作不定期更换。&…

HTTP协议 GET和POST区别 请求响应 Fiddler postman ajax

&#x1f496; 欢迎来阅读子豪的博客&#xff08;JavaEE篇 &#x1f934;&#xff09; &#x1f449; 有宝贵的意见或建议可以在留言区留言 &#x1f4bb; 欢迎 素质三连 点赞 关注 收藏 &#x1f9d1;‍&#x1f680;码云仓库&#xff1a;补集王子的代码仓库 不要偷走我小火…

Mac下nvm安装使用

​欢迎光临我的博客查看最新文章: https://river106.cn 1、简介 nvm 是 Mac 下的 node.js 管理工具。可以通过 nvm 安装和切换不同版本的 node.js。 官网&#xff1a;https://nvm.uihtm.com/ github&#xff1a;https://github.com/nvm-sh/nvm 2、安装 curl -o- https://raw…

移动端适配rem方案

做移动端的适配我们就是要考虑&#xff0c;对于不同大小的手机屏幕&#xff0c;怎么动态改变页面布局中所有盒子的宽度高度、字体大小等。 这个问题我们可以使用相对单位rem。 那么什么是 rem&#xff1f; rem&#xff08;font size of the root element&#xff09;是指相对…

Linux-中断和时间管理(上)

目录 中断的进入过程 中断的进入过程 为方便实验&#xff0c;本章以配套的目标板 FS4412为例来介绍 Linux 的中断子系统&#xff0c;并且编写相应的中断处理程序。FS4412 上的处理器是 SAMSUNG公司的 Exynos4412&#xff0c;该处理器使用的是4核的 Cortex-A9&#xff0c;&…