15.2 STL理念
C++标准库为处理数据序列提供了一个专门的框架,称为STL。STL是标准模板库(Standard Template Library)的简称。STL是ISO C++标准库的部分,它提供了容器(例如vector、list和map)和通用算法(例如sort、f?ind和accumulate)。因此我们可以称vector这类对象为STL或标准库的一部分。标准库的其他部分,例如ostream(第10章)和C风格的字符串处理函数(附录C.10.3),并不属于STL。为了更好地理解STL,我们首先考虑在处理数据时必须要解决的问题和对求解方案的理念。
计算过程包含两个主要方面:计算和数据。有时我们只关注计算方面,谈论if语句、循环、函数和错误处理等。有时我们关注的是数据,谈论数组、向量、字符串和文件等。然而,要完成真正的工作我们需要同时考虑计算和数据。如果对大量数据不进行分析、可视化和查找“感兴趣的部分”,则数据是无法理解的。相反,我们可以随心所欲地进行计算,但是只有与实际数据关联之后,才能避免枯燥乏味的无意义计算。而且,“计算部分”要优雅地与“数据部分”进行交互。
当谈起数据时,我们会想到很多类型的数据:数十个形状、数百个温度值、数千个日志记录、数百万个点、数十亿个网页等,即我们在讨论数据的容器、数据流等。特别地,我们并不是要讨论如何为一个小对象(例如,一个复数、一个温度读数或一个圆形等)选择最恰当的数值。对于这些类型,可以参看第9、11和19章。
考虑我们需要对“大量数据”进行的一些简单操作:
按照字典序排序。
根据姓名在电话本中找到对应的电话号码。
找出温度的最高值。
找出所有大于8800的值。
找出第一个值为17的元素。
根据单元编号对遥测记录进行排序。
根据时间戳对遥测记录进行排序。
找出第一个值大于“Petersen”的元素。
找出最大值。
找出两个序列的第一个不同之处。
计算两个序列中对位元素两两之积。
找出一个月中每天的最高气温。
在销售记录中找出最畅销的10件商品。
统计“Stroustrup”在网页中出现的次数。
计算各个元素之和。
注意,我们在讨论上述数据处理任务时,并没有提到数据如何存储。很显然,我们必须使用链表、向量、文件和输入流等来完成这些任务,但是我们不必了解这些数据存储(或收集)的细节,即可讨论如何对它们进行处理。重要的是这些值或对象的类型(元素类型),我们如何访问这些值或对象,以及要对它们进行什么操作。
这些任务非常常见,我们自然希望能编写代码简单高效地完成这些任务。与之相对,我们需要考虑的问题是:
数据类型(“数据种类”)变化万千。
数据集存储方法多到让人眼花缭乱。
我们想对数据集执行的任务也数量繁多。
为了尽可能降低这些问题的影响,我们希望编写的代码能够处理各种数据类型,处理各种数据存储方法,适用于各种处理任务。换句话说,我们想通过泛化代码来适应各种变化。我们要避免对每一个问题都从头开始寻找处理方法,那样会浪费大量的时间。
为了编写能够达到上述目的的代码,首先用更加抽象的方式来看待我们要对数据进行的处理工作:
收集数据并装入容器。
例如vector、list和数组。
组织数据。
用于打印;
用于快速访问。
提取数据。
通过索引(例如,第42个元素);
通过值(例如,年龄字段是7的第一条记录);
根据属性(例如,所有温度字段大于32小于100的记录)。
修改容器。
增加数据;
减少数据;
排序(根据某种标准)。
进行简单的数值运算(例如,将每一个元素乘以1.7)。
我们在完成上述任务时要避免陷入各种细节之中:各种容器间的差别、各种数据元素访问方法间的差别以及各种数据类型间的差别。如果我们能够做到这一点,就等于向编写简单高效的通用代码的目标迈出了一大步。
回顾前面几章介绍的编程工具和技术,我们(已经)可以编写功能相似但与数据类型无关的代码:
使用int与使用double基本没有差异。
使用vector<int>与使用vector<string>基本没有差异。
使用double类型的数组与使用vector<double>基本没有差异。
我们希望通过合理组织代码,实现只有当我们想要完成一些全新的任务时才需要编写新的代码。特别是,我们希望编写一些完成基本任务的代码,使得我们不必每次发现一种新的数据存储方式或数据解释方式时都重写整个程序。
在vector中查找一个值与在数组中查找一个值差异不大。
查找string时不区分大小写与区分大小写的差异不大。
绘制实验数据图时使用准确值与使用四舍五入值的差异不大。
拷贝文件与拷贝vector对象的差异不大。
根据上面的发现,我们希望编写的代码具有以下特点:
容易阅读。
容易修改。
规范。
简短。
快速。
为了简化编程工作,我们会:
使用统一的方式访问数据。
与数据存储方法无关;
与数据类型无关。
使用类型安全的方式访问数据。
便于遍历数据。
紧凑存储数据。
快速
读取数据;
增加数据;
删除数据。
对通用算法提供标准实现。
例如拷贝、查找、搜索、排序、求和等。
STL提供了上述功能以及更多。我们不应仅仅将它看作一个强大的功能库,更应看作一个兼顾灵活性与性能的函数库设计的典范。STL由Alex Stepanov设计,提供了一个作用于数据结构之上的通用、正确和高效的算法框架。其设计理念满足简单性、通用性和数学上的优雅。
除了使用设计理念和原则清晰的框架来处理数据之外,另一种策略是让程序员使用最基本的语言特性从头开始编写每个程序,并采用一些当时看起来不错的思想。这种方式费时费力,而且得到的程序代码往往非常糟糕,毫无章法可言,除作者之外的人很难理解,而且在其他场合能够复用的可能性微乎其微。
在介绍完STL的设计初衷和理念之后,我们会给出STL的一些基本定义,最后通过例子展示如何在实际应用中运用这些基本理念:编写更好的处理数据的代码,而且让编写过程更简单。