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

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;
}

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android类似微信首页的页面开发教程(Kotlin)二

前提条件 安装并配置好Android Studio Android Studio Electric Eel | 2022.1.1 Patch 2 Build #AI-221.6008.13.2211.9619390, built on February 17, 2023 Runtime version: 11.0.150-b2043.56-9505619 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. Windows 11 …

【Vue】学习笔记-Vue生命周期

引出生命周期 生命周期 a.又名生命周期回调函数、生命周期函数、生命周期钩子 b.是什么&#xff1a;vue 在关键时刻帮助我们调用一些特殊名称的函数 c.生命周期函数的名字不可更改&#xff0c;但函数的具体内容是程序员根据需求编写的 d.生命周期函数中的this指向是vm或组件实…

拷贝构造与深浅拷贝

文章目录 一、拷贝构造函数二、拷贝初始化三、深浅拷贝 一、拷贝构造函数 如果一个构造函数的第一个参数是自身类型的引用&#xff0c;而且任何额外参数都有默认值&#xff0c;则此构造函数是拷贝构造函数。 class person { public: person(); //默认构造函数 pe…

米文动力 EVO Orin 刷机和克隆操作说明

刷机说明 博主在卸载 cuda 以及 python 后重启后黑屏无法显示&#xff0c;重刷系统才恢复正常。 下载 EVO Orin 用户手册&#xff08;官网没有&#xff0c;所以上传到 CSDN 供下载&#xff09;官网下载 EVO Orin 镜像文件 使用 tar -xvf 解压下载的 bootloader 和镜像包得到 …

计算机办公自动化——Python批量生成请假条

Python使用openpyxl、docx批量生成请假条 前言第三方库的安装示例代码运行效果 前言 加入你有一个下图所示的表格&#xff0c;需要批量生成他们的请假条&#xff0c;你会选择如何做呢&#xff1f;是一步一步的手打&#xff0c;还是呼唤请假人手打呢&#xff1f; 下面我们来看…

react中前端同学如何模拟使用后端接口操作数据?

为什么前端同学需要模拟后端数据 作为一个前端&#xff0c;在实现项目功能的时候&#xff0c;需要在前端写一个静态的json数据&#xff0c;进行测试。 项目中后端的接口往往是较晚才会出来&#xff0c;并且还要写接口文档&#xff0c;于是我们的前端的许多开发都要等到接口给…

基于ArcGIS Pro、R、INVEST等多技术融合下生态系统服务权衡与协同动态分析

生态系统服务是指生态系统所形成的用于维持人类赖以生存和发展的自然环境条件与效用&#xff0c;是人类直接或间接从生态系统中得到的各种惠益。联合国千年生态系统评估&#xff08;Millennium ecosystem assessment&#xff0c;MA&#xff09;提出生态系统服务包括供给、调节、…

[pgrx开发postgresql数据库扩展]4.基本计算函数的编写与性能对比

前言 再次声明&#xff1a; 并不是所有场景都需要&#xff08;或者适合&#xff09;用rust来写的&#xff0c;绝大部分操作数据库的功能和计算&#xff0c;用SQL就已经足够了&#xff01; 本系列中&#xff0c;所有的案例&#xff0c;仅用于说明pgrx的能力&#xff0c;而并非…

Docker --- 简介、安装

一、什么是Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。 在数百上千台服务中重复部署&#xff0c;环境不一定一致&#xff0c;会…

基于Java+SpringBoot+vue学生学习平台详细设计实现

基于JavaSpringBootvue学生学习平台详细设计实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目…

用SQL语句操作Oracle数据库——数据更新

数据更新 数据库中的数据更新操作有3种&#xff1a;1)向表中添加若干行数据&#xff08;增&#xff09;&#xff1b;2&#xff09;删除表中的若干行数据&#xff08;删&#xff09;&#xff1b;3&#xff09;修改表中的数据&#xff08;改&#xff09;。对于这3种操作&#xf…

seleniumUI自动化登录失败案例重新尝试WhileTrue

一个用户每次登录失败&#xff0c;失败N次&#xff0c;无法进入下一url时&#xff0c;怎样会重新尝试N次重新登录呢 &#xff1f; 我们可以使用wihile true判断&#xff0c;并使用currenturl判断&#xff0c;下面就介绍以下个人的方法 currenturlEGTconfigFile.driver.curren…

学系统集成项目管理工程师(中项)系列11b_沟通管理(下)

1. 沟通过程的有效性 1.1. 效果 1.1.1. 在适当的时间、适当的方式、信息被准确的发送给适当的沟通参与方&#xff08;信息的接收方&#xff09;&#xff0c;并且能够被正确的理解&#xff0c;最终参与方能够正确的采取行动 1.2. 效率 1.2.1. 强调的是及时提供所需的信息 2…

深度学习 - 43.SeNET、Bilinear Interaction 实现特征交叉 By Keras

目录 一.引言 二.SENET Layer 1.简介 2.Keras 实现 2.1 Init Function 2.2 Build Function 2.3 Call Function 2.4 Test Main Function 2.5 完整代码 三.BiLinear Intercation Layer 1.简介 2.Keras 实现 2.1 Init Function 2.2 Build Function 2.3 Call Functi…

使用AI优化慢SQL,开发秒变DBA

“AI不会替代他们&#xff0c;但善用AI的人会” 慢 SQL 经常会让应用程序响应变慢&#xff0c;轻者影响用户体验&#xff0c;严重的时候可能会导致服务不可用。如果&#xff0c;每次遇到慢 SQL 都求助于 DBA&#xff0c;一方面效率很低&#xff0c;另一方面也会很没面子。所以…

聊聊如何通过APT+AST来实现AOP功能

前言 如果有使用过spring aop功能的小伙伴&#xff0c;应该都会知道spring aop主要是通过动态代理在运行时&#xff0c;对业务进行切面拦截操作。今天我们就来实现一下如何通过APTAST在编译期时实现AOP功能。不过在此之前先科普一下APT和AST相关内容 APT&#xff08;注解处理…

openEuler-linux下部署zabbix-超级详细

一、准备工作 下载&#xff1a;zabbix包 地址&#xff1a;下载Zabbix 准备2台openEuler-linux虚拟机&#xff1a; linux-1&#xff1a;当服务器端 IP地址&#xff1a;192.168.100.100 修改hosts文件 [rootzbx ~]# vim /etc/hosts 192.168.100.100 zbx.xx.cn linux-2&…

[Java]JavaWeb开发中的MVC设计模式

一、有关Java Web与MVC设计模式 学习过基本Java Web开发的人都已经了解了如何编写基本的Servlet&#xff0c;如何编写jsp及如何更新浏览器中显示的内容。但是我们之前自己编写的应用一般存在无条理性&#xff0c;对于一个小型的网站这样的编写没有任何问题&#xff0c;但是一但…

ETL工具-pentaho企业实战部署

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

TinyOS 配置教程

系列文章目录 TinyOS 系列文章【一】&#xff1a;TinyOS 配置教程 TinyOS 系列文章【二】&#xff1a;Tossim 教程 文章目录 系列文章目录前言1. 安装1.1. 实验环境1.2. TinyOS基础工作1.3. TinyOS 的配置1.4. 安装 java1.5. 安装编译器 2. 测试仿真程序总结 前言 本文主要用…