前言
Standard Template Library(STL)主要由两部分组件构成:一个是容器(container),包括vector、list、set、map等类,另一种组件是用以操作这些容器类的所谓泛型算法(generic algotithm),包括find(),sort(),replace(),merge()等等
vector和list这两种容器室所谓的序列式容器(sequentialcontainer),序列式容器会依次维护第一个元素、第二个元素……直到最后一个元素。我们在序列式容器上主要进行所谓的迭代(iterate)操作,map和set这两种容器属于关联式容器,关联式容器可以让我们快速寻找容器中的元素值。
所谓map是一对对的key/value组合,key用户搜寻,value用来表示我们要存储或取出的数据。例如,电话号码可以轻易用map表示,电话用户名便是key,而value与电话号码产生关联。
所谓set,其中仅含有key,我们队它进行查询操作,为的是要判断某值是否在于其中,如果我们想要建立一组索引表,用来记录新闻,故事中出现的子,我们可能会希望将一些中性字眼,比如the、an、but排除掉,在放行某个字,让它进入索引表前,我们先查询excluded_word这么一个set,如果这个字存在其中,我们便忽略它,不再计较,反之则将此字加入索引表。
所谓泛型算法,提供了许多可施行于容器类及数组型别上的操作行为,这些算法之所以被称为泛型(generic),因为它们和它们想要操作的元素型别无关,比如int,double或string无关,它们同样也和容器型别彼此独立,无论是vector、list或array。
泛型算法通过function template技术,达成“与操作对象之型别相互独立”的目的。而达成“与容器无关”的诀窍,就是不要直接在容器身上进行操作,取代方式是,藉由一堆iterators (first, last)、表示我们欲进行迭代的元素区间。如果first等于last,算法便只作用于first元素,如果first不等于last,算法便会首先作用于first所指元素身上,并将first前进一个位置,然后再作用于当前的first所指元素身上,如此持续进行,知道first等于last位置。
泛型指针 Iterators
我们需要设计一组iterator classes,让我们可以使用和指针相同个的语法来进行程序的撰写。举个例子,如果first和last都是list的iterators,我们可以这样写
while (first!=last)
{
cout<< *first << ‘ ’;
++first;
}
这就像吧first和last当做指针一样,唯一的区别在于其dereference, !=, ++是由iterators classes 内相关的inline函数提供的。
如何取得iterators?
每个标准容器都提供一个名为begin()的操作函数,可返回一个iterator,指向第一个元素;另一个end()的操作函会返回一个iterator,指向最后一个元素的下一个位置。以下是对iterator进行assign, compare,increment, dereference操作:
for (iter = svec.begin()); iter != svec.end();++iter)
cout<< *iter << ‘ ’;
哪些信息是这份定义应该提供的:
(1) 迭代对象(某个容器)的类别,这可以用来决定如何存取下一个元素
(2) iterator所指的数据型别,这可以决定iterator提领操作的返回值
iterator的一种可能的定义形式,便是将上述的两个型别作为参数,传给iterator class:
//iterator的一种可能的定义形式
//这不是STL的做法
iterator <vector, string> iter;
实际语法看起来复杂一些,并提供更优雅的解法,虽然后者可能并不十分明显,但是当我们实现并运用iterator class后,会有所体会。
vector<string> svec;
//以下是标准程序库中的iterator语法
//iter指向一个vector,后者的元素型别为string
//iter一开始指向svec的第一个元素
vector<string>::iterator iter =svec.begin();
此处的iter被定义为一个iterator,指向一个vector,后者的元素型别为string,其初值指向svec的第一个元素,式中的::表示此iterator是位于string vector定义式内的嵌套(nested)型别。
对于const vector:
const vector<string> cs_vec;
我们使用const_iterator来进行遍历操作:
vector<string>::const_iterator iter =cs_vec.begin();
const_iterator允许我们读取vector的元素,但是不允许任何写入操作。
vector<elemType>::const_iteratoriter = vec.begin();
vector<elemType>::const_iteratorend_ti = vec.end();
display()函数重新翻修后的面貌
template <typename elemType>
void display(constvector<elemType> & vec, ostream & os)
{
vector<elemType>::const_iteratoriter = vec.begin();
vector<elemType>::const_iteratorend_ti = vec.end();
for(; iter != end_it; ++iter)
os<< *iter << ‘ ’;
os<< endl;
}
重新设计find(),让它同时支持两种形式:一对指针或者是一对iterators
template <typename IteratorType,typename elemType>
IteratorType
find(IteratorType first, IteratorTypelast, const elemType &value)
{
for( ; first != last; ++first)
if(value == *first)
returnfirst;
returnlast;
}