概述
第二章 C++ STL
本章节所介绍的C++ STL主要基于三个内容:迭代、算法和容器。所参考的资料均来自于CSDN博客以及P.J.PLAUGER所著的《C++ STL中文版》。主要的参考文献将在本书最后给出。
2.1 C++ STL简介
STL(Standard Template Library)标准模板库是惠普实验室开发的一系列软件的统称。标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
STL代码从广义上大致分为3类:算法algorithm,容器container和迭代器iterator。算法是决定结果的一个数学过程。STL容器是一些模板类,迭代器用于联系算法和容器。几乎STL所提供的所有算法都是通过迭代器存储元素序列进行工作的。STL中的每一个容器都定义了其本身所专有的迭代器,用以存取容器中的元素。
container容器 | algorithm算法 | iterator算法 |
数组、堆栈、队列、链表或二叉树、红黑树 | 排序、增删、改查等 | 访问容器的一种类似于指针的工具 |
2.1.1 功能描述
组成C++中STL部分的头文件由以下13个组成,可以使用include指令将标准头文件中的内容包含到程序中,如下。
algorithm | deque | functional | iterator | list |
map | memory | numeric | queue | set |
stack | utility | vector |
|
|
#include<algorithm>//include all algorithms
STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用。例如,由于STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组;
STL另一个重要特性是它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。你在STL中找不到任何明显的类继承关系。这好像是一种倒退,但这正好是使得STL的组件具有广泛通用性的底层特征。另外,由于STL是基于模板,内联函数的使用使得生成的代码短小高效;
2.1.2 使用STL
一、命名空间
using namespace std;
这样做会使所有在库中定义的名字都暴露在当前的命名空间中,于是就不需要在这些名字前添加前缀std::。如果想把库中定义的所有名字都暴露在全局命名空间,则需要在每个源文件的开始处都写上这句声明。
二、头文件
头文件通常被用于解释的注释以及用于防范措施的守卫宏所包围。如utility文件:
Eg:
//utility standard header
#ifndef _UTILITY_
#define _UTILITY_
……
#endif /* _UTILITY_ */
这种方法可以防止一个头文件被程序包含多次。
2.2 STL迭代器
概括来说,迭代器在STL中用来将算法和容器联系起来,起着一种黏和剂的作用。迭代器部分主要由<utility>,<iterator>和<memory>三个头文件为基础展开讨论。
<utility>是一个很小的头文件,它包括了贯穿使用在STL中的几个模板的声明。
<iterator>中提供了迭代器使用的许多方法,而对于<memory>的描述则十分的困难,它以不同寻常的方式为容器中的元素分配存储空间,同时也为某些算法执行期间产生的临时对象提供机制,<memory>中的主要部分是模板类allocator,它负责产生所有容器中的默认分配器。
2.2.1 功能描述
C++中的迭代器相对于C中的对象指针来说更加一般化,指针本身就可以作为定义好的迭代器来使用。
一、输出迭代器
可使用迭代器来存取有序序列中的元素,“存取”既可以表示将值存储到对象中,也可以表示从一个对象中获得它所保存的值。
例 2.2.1 创建新的序列,并以有序方式产生值。
for (;<not done>;++next)
//next表示一个迭代器类型为X的对象,<not done>用于检测终止条件
*next=<whatever>;//<whatever>是一个表达式
输出迭代器的属性 | |||
表达式 | 结果的类型 | 含义 | 注释 |
X(a) | X | 产生一个a的拷贝 | *X(a)=t与*a=t作用相同 |
X u(a) X u=a | X& | u是a的拷贝 |
|
X是迭代器类型;a的类型为X&,T是元素类型,t的类型为T。 |
一个输出迭代器至少需要定义以下操作:
- *next=<whatever>:将<whatever>的值赋给序列中将要产生的下一个元素。
- ++next改变next的值,使其指向序列中的下一个元素。
二、输入迭代器
输入迭代器用于产生新的序列。用于顺序存取已有的值或对已有的序列进行遍历。
Eg:
for (p=first;p!=last;++p)//p,first和last都是迭代器类型X的对象
<process>(*p);//<process>是一个函数,能够接受元素类型为T的参数
//其中first和last各代表一个迭代器
输入迭代器至少需要定义以下操作:
- 当两个类型为X的迭代器p和q没有指向同一个元素时,p!=q就为真。
- *p是类型T的一个右值。
- ++p改变p的值,将它指向序列中目前所指向元素的下一个元素。
输入迭代器的属性 | |||
表达式 | 结果的类型 | 含义 | 注释 |
X(a) | X | 产生一个a的拷贝 | *X(a)与*a作用相同 |
X u(a) X u=a | X& | u是a的拷贝 | 创建完成后u==a |
X是迭代器类型;a的类型为X&,T是元素类型,t的类型为T。 |
三、end of sequence值
该值由输入迭代器定义,它在大多数情况下是一种end of file标记,end of sequence值通常存储在last中,用于记录迭代器first是否等于last。即我们可以通过增加输入迭代器的值来遍历一个文件。
四、前向迭代器
输入/输出迭代器可以处理任意长度的文件,但是迭代器的更加普遍的用法是:存取一个完全存储在内存中的序列。使用前向迭代器可是实现序列中元素的同时读和写,也可以实现“书签”操作。在这些情况下,迭代器更像一个传统的指针。
可以把前向迭代器想象成为一个指向单链表中元素的指针,如果它指向的不是链表的末端,则就可以通过它来存取链表中的元素,或是把它移到序列中下一个元素的位置。但是不能通过它来直接存取链表中的任意元素。
五、双向迭代器
这一种迭代器可以同时支持递增递减操作。可以将其想象为指向一个双向链表中元素的指针。用null来标记end of sequence。若迭代器指向的不是链表的末端,则可以通过它来存取链表中的元素,或者向下移位。若迭代器指向的不是链表中第一个元素,则可以把它回退到序列中前一个元素的位置。
六、随机存取迭代器
不再赘述。
2.2.2 功能描述
STL中大量使用了迭代器,它们用于不同的算法和算法所做用的序列之间,起着桥梁的作用。下面总结了一些常用的迭代器。
OutIt输出迭代器 | 若X为一个输出迭代器,则它只能通过存储来间接地拥有一个值V,且在存储值之后,需要递增。 (*X++=V)或者(*X=V,X++) |
InIt输入迭代器 | 若X为一个输入迭代器,若它的值不等于end of sequence的话,就可以通过间接的方式来存取它所拥有的值V。 (V=*x) 若想取得序列中下一个元素的值,则需将其递增。如++X,或*V=X++ |
FwdIt前向迭代器 | 若X为一个前向迭代器,如果*X是可变的,那么它就可以替换输出迭代器,同理也可以替换输入迭代器。 |
BidIt双向迭代器 | 若X为一个双向迭代器,则其可以替换前向迭代器。 |
RanIt随机存取迭代器 |
|
迭代器的种类:
只写操作(write only) | 只读操作(read only) | 读写操作(read/write) |
输出迭代器可以被替换为: 前向迭代器 双向迭代器 随机存取迭代器 | 输入迭代器可以被替换为: 前向迭代器 双向迭代器 随机存取迭代器 | 前向迭代器可以被替换为: 双向迭代器 随机存取迭代器 |
对象指针总是可以当作随机存取迭代器来使用。
最后
以上就是精明夕阳为你收集整理的C++进阶与拔高(四)(C++ STL迭代器)第二章 C++ STL的全部内容,希望文章能够帮你解决C++进阶与拔高(四)(C++ STL迭代器)第二章 C++ STL所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复