当前课程知识点:基于Linux的C++ > 第十一讲 泛型编程 > 11.11 泛型编程实践(三) > LinuxCPP1111
我们来看主函数的具体实现
我们定义一个整型向量 a
生成这些整数 然后调用 Display() 显示它
现在你能够看得清了吧
我们传的实际参数是
a、“Array generated”这个字符串
我们首先会输出这行文本
然后输出 a 这个向量
它的每一个元素都会被输出
然后定义 vector〈int〉::iterator head, tail
把它们分别初始化成 a.begin()、a.end()
然后我调用标准算法库里边的 sort()
对这个整型向量进行排序
sort() 不是标准库里面的那个 qsort()
虽说它也是快速排序 但是它并不是 qsort()
它是标准模板库里边的 sort()
它是一个抽象的排序算法
传的就是 head 和 tail 这两个迭代器
一个指向 0 号元 一个指向过尾元
然后它就帮你对这个向量进行排序了
实际上 它不仅仅可以排序向量
只要支持迭代器 sort() 都可以排序
不管它是向量
还是我们后面要谈到的表啊
其他什么东西 都可以进行排序
缺省排序方式是从小到大的
你可以 Display()
就可以看到它排序后的结果
你想按从大到小排序怎么办呢 简单
调用一次标准模板库里面 reverse() 这个函数
reverse() 就完成这个数据的翻转
同样传两个迭代器
reverse() 就能够把这个整型向量
所有的元素全部翻转过来
这不就是从大到小了嘛
然后你再 Display()
把它输出出来 就 OK 了
这是输出流迭代器
下一个例子就是输入流迭代器
我可以定义一个整型向量 v(4)
包含 4 个元素 然后定义它的迭代器
设为 v.begin()
我输出一个提示信息
就是请你输入 4 个整数
中间用空格分割开
最后再输入一个字符
它是按照这个模式输入
然后我定义一个输入流迭代器 head
把它和 cin 挂接在一起
定义一个空的迭代器 tail
表示它的结束
copy(head, tail, it)
head 和 tail 都是输入流的迭代器
head 表示输入流的开头
tail 表示输入流的结尾
这个输入流结束了 我们就结尾
用它来指代 对吧
刚才讲过了 it 就是整型向量的迭代器
接下来你在程序运行的时候
你就会通过键盘输入一系列的整数
中间用空格分隔开
最后再输入一个字符的时候
它就读一个整数
把它放到 it 所指代的那个整型向量里
然后再读一个整数
再把它放到整型向量里
它就按照这个方式
一个接着一个地将元素拷贝到了
我们的整型向量里
而数据的来源是你通过键盘输入的
输入完了以后
我们 cin.clear() 清除输出流
你可以写一个循环
通过这个迭代器来遍历整型向量
看一看这些数据
有没有被正确地输入到我们的整型向量里
当你使用循环来遍历我们的容器的时候
它的基本格式是这样的:
for( it = v.begin(); it != v.end(); it++ )
接下来一个容器就是表
标准模板库里边实现的这个表
实际上是一个双向的链表
表的使用方式和向量类似
但是它的功能要比向量要多 要复杂
在实现上和向量也有很大的不同
你比如讲 如果我要定义
包含 Point 对象一个容器
这样一个表的话
那么你就可以写 list〈Point〉 pts(8)
这表示定义能够容纳 8 个 Point 对象的
这样一个表 就是我们的链表 list
双向链表
想在这个链表中插入
你就可以调用它的成员函数 insert()
想在它的表头插入
就可以调用它的成员函数 push_front()
想在表尾插入就是 push_back()
你也可以定义指向 point 类的
对象的指针的容器
list〈Point *〉pts(8)
就表示我们定义 8 个元素的一个表
这个表里面保存的元素呢
不再是 Point 类的对象
而是指向 Point 类对象的指针
这个方式也可以
插入、删除 动作是一样的
你只需要记住 这个时候插入的实际上是那个对象的地址
你只需要记住 这个时候插入的实际上是那个对象的地址
而不是那个对象本身 就可以了
对于一个表的操作来讲
对于一个复杂数据结构
我们往往保存的是它的指针
而不是那个对象本身
如果是那个对象本身
它可能会涉及到频繁地数据的拷贝动作
实际上程序效率是不会高的
特别去注意这一点
如果你要想知道这个表是空的
还是不是空的
那么你就可以使用它的成员函数 empty()
来获取它的信息
表的迭代器和向量的迭代器类似
但是它们毕竟是两个不同的东西
就像我前面讲的
每一个容器都有与它相适应的迭代器
容器和迭代器本身是紧密相关的
因为不同的容器存储那些数据
和管理那些数据的方式是不一样的
所以每一个容器都有与它相适应的迭代器
表的迭代器
你按照这样的一个方式来写
list〈int〉::iterator
这就是把 vector 换成了 list
这个就是我们表迭代器的型式
你就按照这个方式写就可以了
for( it = a.begin(); it != a.end(); it++ )
接下来就是 *it = GenerateRandomNumber( 10, 99 )
你按照这个方式
就可以把生成的这些整数
插入到了这个表里边
就按照这个方式去写就可以了
想要对表进行排序
你可以调用表的成员函数 sort()
它就可以完成排序的动作
当然默认仍然是升序的
如果你想降序的排序 还是我们刚才说的
排好了升序之后 调用一次成员函数 reverse()
它就可以给你逆过来 这是一个
第二个你可以在排序的时候传入一个函子
greater_equal〈int〉()
greater_equal〈int〉是标准模板库里边
给我们提供好的标准函子
它是大于等于函子
你用int对这个模板进行体化
形成一个模板类
在这个模板类上面
它重载了函数调用操作符
所以它的很多功能就像函数指针一样
这一点我们后面会讨论
在这里 你必须传一个
通过这个类构造的一个匿名对象
作为函数参数传给 sort()
sort() 就能够按照你指定的方式对这个表进行排序
sort() 就能够按照你指定的方式对这个表进行排序
对于一个自定义的对象
需要你重载 operator〈
这个大小比较关系
这个操作符你必须重载
因为你自定义的对象
编译器本身是不知道怎么对它进行排序的
所以你必须重载这个操作符
否则的话 这个排序是没有办法工作的
我们后面会有例子给大家展示怎么写
在 C++ 标准模板库里边
提供了一系列的算法
包括查找算法、排序算法、
删除和替换算法、排列组合算法、
算术算法、关系算法、集合算法、
生成和变异算法、堆算法 等等
好几十个函数 你都可以用
所有的这些算法都是抽象的
它完成的是一个抽象的数据的操作
包括查找 包括排序 全都是抽象的
基本上都带迭代器参数
你比如讲 all_of
我们看第二个
当给定区间内全部元素均满足条件时
它会返回 true
就是这样一个标准算法 基本上都是
按照像这样的一个格式
标准模板库里边提供标准算法很多
这些算法的使用相当类似
因为这些算法都带有迭代器
所以它的使用方式基本类似
你就按照标准模板库里边的说明
去调用就可以了
我们这里就把这些标准算法的名字
和它简要的介绍给大家罗列在这里
是给大家查的
这些函数的具体的内容
我们就不一一解释了
打开帮助手册一看就明白了
如果你还不明白
帮助手册里边一般都会提供一些示例
你看一下那个示例
运行一下你就明白了
我们的一页是 10 个标准算法
这是第二页
第三页
这是第四页
这是第五页
这是第六页
这是第七页
这是第八页
第九页
你看标准库里边给我们提供了
多少个抽象算法 84 个
很多算法让我们自己实现的时候
实际上是很麻烦的
而在标准的模板库里边
已经给我们完全提供好了
你拿过来直接用就行了
所以实际上是极大地降低了
我们的编程工作量
会用标准模板库是非常非常重要的
在标准模板库里边
它还提供了一系列的标准函子
包括算法函子 包括关系函子
也包括逻辑函子
算术函子是这么六个:
加、减、乘、除、取模、取负六个
关系函子也提供了六个:
等于、不等于、大于、大于等于、
小于、小于等于
就按照这个模式
它后面都带着型式参数
然后是提供了三个逻辑函子:
逻辑与、逻辑或、逻辑非
你可以直接使用这些标准的函子
-1.1 提纲
-1.2 程序设计的基本概念
-1.3 简单C/C++程序介绍
-1.4 程序设计的基本流程
-1.5 基本语法元素
-1.6 程序设计风格
-1.7 编程实践
-第一讲 C/C++基本语法元素--编程实践提交入口
-2.1 提纲
-2.2 结构化程序设计基础
-2.3 布尔数据
-2.4 分支结构
-2.5 break语句
-2.6 循环结构
-2.7 编程实践
-第二讲 程序控制结构--编程实践提交入口
-3.1 提纲
-3.2 函数声明、调用与定义
-3.3 函数调用栈框架
-3.4 编程实践
-第三讲 函数--编程实践提交入口
-4.1 提纲
-4.2 算法概念与特征
-4.3 算法描述
-4.4 算法设计与实现
-4.5 递归算法(一)
-4.6 递归算法(二)
-4.7 容错与计算复杂度
-4.8 编程实践
-第四讲 算法--编程实践提交入口
-5.1 提纲
-5.2 库与接口
-5.3 随机数库(一)
-5.4 随机数库(二)
-5.5 作用域与生存期
-5.6 典型软件开发流程(一)
-5.7 典型软件开发流程(二)
-5.8 编程实践
-第五讲 程序组织与开发方法--编程实践提交入口
-6.1 提纲
-6.2 字符
-6.3 数组(一)
-6.4 数组(二)
-6.5 结构体
-6.6 编程实践
-第六讲 复合数据类型--编程实践提交入口
-7.1 提纲
-7.2 指针基本概念
-7.3 指针与函数
-7.4 指针与复合数据类型(一)
-7.5 指针与复合数据类型(二)
-7.6 字符串
-7.7 动态存储管理(一)
-7.8 动态存储管理(二)
-7.9 引用
-7.10 编程实践
-第七讲 指针与引用--编程实践提交入口
-8.1 提纲
-8.2 数据抽象(一)
-8.3 数据抽象(二)
-8.4 链表(一)
-8.5 链表(二)
-8.6 链表(三)
-8.7 链表(四)
-8.8 函数指针(一)
-8.9 函数指针(二)
-8.10 抽象链表(一)
-8.11 抽象链表(二)
-8.12 编程实践
-第八讲 链表与程序抽象--编程实践提交入口
-9.1 提纲
-9.2 程序抽象与面向对象
-9.3 类类型
-9.4 对象(一)
-9.5 对象(二)
-9.6 类与对象的成员(一)
-9.7 类与对象的成员(二)
-9.8 类与对象的成员(三)
-9.9 继承(一)
-9.10 继承(二)
-9.11 继承(三)
-9.12 多态(一)
-9.13 多态(二)
-9.14 编程实践
-第九讲 类与对象--编程实践提交入口
-10.1 提纲
-10.2 四则运算符重载(一)
-10.3 四则运算符重载(二)
-10.4 关系与下标操作符重载
-10.5 赋值操作符重载(一)
-10.6 赋值操作符重载(二)
-10.7 赋值操作符重载(三)
-10.8 赋值操作符重载(四)
-10.9 赋值操作符重载(五)
-10.10 流操作符重载(一)
-10.11 流操作符重载(二)
-10.12 流操作符重载(三)
-10.13 操作符重载总结
-10.14 编程实践
-第十讲 操作符重载--编程实践提交入口
-11.1 提纲
-11.2 泛型编程概览
-11.3 异常处理机制(一)
-11.4 异常处理机制(二)
-11.5 运行期型式信息(一)
-11.6 运行期型式信息(二)
-11.7 模板与型式参数化
-11.8 题外话:术语翻译
-11.9 泛型编程实践(一)
-11.10 泛型编程实践(二)
-11.11 泛型编程实践(三)
-11.12 泛型编程实践(四)
-11.13 泛型编程实践(五)
-11.14 泛型编程实践(六)
-11.15 泛型编程实践(七)
-11.16 泛型编程实践(八)
-11.17 泛型编程实践(九)
-11.18 泛型编程实践(十)
-11.19 编程实践
-第十一讲 泛型编程--编程实践提交入口
-12.1 提纲
-12.2 程序执行环境(一)
-12.3 程序执行环境(二)
-12.4 程序执行环境(三)
-12.5 程序执行环境(四)
-12.6 输入输出(一)
-12.7 输入输出(二)
-12.8 文件系统
-12.9 设备
-12.10 库(一)
-12.11 库(二)
-12.12 makefile文件(一)
-12.13 makefile文件(二)
-12.14 makefile文件(三)
-12.15 编程实践
-第十二讲 Linux系统编程基础--编程实践提交入口
-13.01 提纲
-13.02 进程基本概念
-13.03 信号
-13.04 进程管理(一)
-13.05 进程管理(二)
-13.06 进程管理(三)
-13.07 进程间通信(一)
-13.08 进程间通信(二)
-13.09 进程间通信(三)
-13.10 进程间通信(四)
-13.11 进程池
-13.12 编程实践
-第十三讲 进程编程--编程实践提交入口
-14.1 提纲
-14.2 线程基本概念
-14.3 线程管理(一)
-14.4 线程管理(二)
-14.5 线程管理(三)
-14.6 线程管理(四)
-14.7 线程同步机制(一)
-14.8 线程同步机制(二)
-14.9 C++11线程库(一)
-14.10 C++11线程库(二)
-14.11 C++11线程库(三)
-14.12 C++11线程库(四)
-14.13 C++11线程库(五)
-14.14 编程实践
-第十四讲 线程编程--编程实践提交入口
-15.1 提纲
-15.2 Internet网络协议
-15.3 套接字(一)
-15.4 套接字(二)
-15.5 编程实践
-第十五讲 网络编程--编程实践提交入口