①容器containers,用来管理某类对象的集合,为了应对不同的需求,STL 准备了不同的容器类型。
② 迭代器Iterators,用来在一个对象群集的元素上进行遍历动作。迭代器的主要好处是为所有容器提供了一组很小的公共接口,利用这个接口,某项操作就可以进行至群集内的下一个元素。
③算法Algorithm,用来处理集群内的元素,可以出于不同的目的使用那些元素。通过迭代器的帮助,只需要撰写一次算法,就可以将它应用在任意容器上。
STL的基本观念就是将数据和操作分离,数据由容器类别加以管理,操作则由可定制的算法定义。迭代器在两者之间充当粘合剂,使任何算法都可以和任何容器交互运作。
容器用来管理一组元素,为了适应不同需要,STL提供了不同类型的容器,总体上可以分为两类:
①序列式容器。是可序群集,其中每个元素均有固定位置——取决于插入时机和地点,与元素值无关。如果以追加方式对一个群集置入元素,它们的排列顺序将和置入次序一致。STL提供了三个此类容器:vector、deque、list
②关联式容器。是已序群集,元素位置取决于特定的排序准则,如果以追加方式对一个群集置入元素,它们的排列顺序取决于元素值,和插入次序无关。STL提供了四个此类容器:set、multiset、map、multimap
序列式容器:
- vector
vector将其元素置于一个动态数组中加以管理。允许随机存取,即就是可以利用索引直接存取任何一个元素,在尾部添加元素或删除元素非常快速,但是在头部或中部安插元素比较费劲,为了保持原本的相对次序,安插点之后的所有元素都必须移动。
下面的例子针对整数类型定义了一个vector,并填充6个元素
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> col;
for(int i=1;i<=6;++i)
{
col.push_back(i);
}
for(int i=0;i<col.size();++i)
{
cout<<col[i]<<" ";
}
cout<<endl;
}
输出结果如下
- Deque
deque,就是“double-ended queue"的缩写。它是一个动态数组,可以在两端对其进行操作,因此不论在尾部还是头部安插删除元素都非常迅速,而在中间部分对元素进行操作时必须移动其他元素,所以比较费时。
声明一个浮点数类型的deque,并在头部安插1.1到6.6共6个元素。
#include<iostream>
#include<deque>
using namespace std;
int main()
{
deque<float> col;
for(int i=1;i<=6;++i)
{
col.push_front(i*1.1);
}
for(int i=0;i<col.size();++i)
{
cout<<col[i]<<" ";
}
cout<<endl;
}
~
输出结果为
我们可以观察到最终元素结果与安插次序恰好相反,因为每个元素都安插在上一个元素的前面。当然也可以使用push_back()在尾部添加元素,此时元素的顺序又会发生变化
- List
List由双向链表组成,这意味着list内的每个元素都有部分内存用来指示其前趋元素和后继元素。List不提供随机存取,因此如果要对某一元素进行操作,则必须按链表顺序依次走过前面的元素。List的优势是在任何位置安插或删除元素都非常快,因为只需改变链接就行。
下面例子产生一个空list,将‘a'至'z’的所有字符插入其中,利用循环每次打印并移除集群的首元素,从而打印出所有元素
#include<iostream>
#include<list>
using namespace std;
int main()
{
list<char> col;
for(char c='a';c<='z';++c)
{
col.push_back(c);
}
while(!col.empty())
{
cout<<col.front()<<" ";
col.pop_front();
}
cout<<endl;
}
运行结果如下
其成员函数empty()的返回值告诉我们容器中是否还有元素,而成员函数front()会返回第一个元素,成员函数pop_front()函数会删除第一个元素。
也可以将string当作STL容器来使用,它和vectors很相似,只不过其元素为字符。
另一种容器不是类别(class),而是C++语言核心所支持的一个型别:具有静态大小或动态大小的array,但array并非STL容器,它们并没有类似size(),empty()等成员函数,尽管如此,STL的设计允许针对array调用STL算法。
关联式容器
上面列举的几种STL容器都是序列式容器,接下来将介绍关联式容器,其依据特定的排序准则,自动为其元素排序,排序准则以函数形式呈现,用来比较元素值或元素键。缺省情况下默认以operator<进行比较。
关联式容器的差别主要在于元素的类型以及处理重复元素时的方法。
- set。其内部元素依据其值自动排序,每个元素值只能出现一次,不允许重复;
- Multiset。它和set相同,只不过它允许重复元素,也就是说multiset可包括多个数值相同的元素;
下面展示如何在set中安插元素,并使用迭代器打印他们
#include<iostream>
#include<set>
using namespace std;
int main()
{
set<int> col;
col.insert(3);
col.insert(1);
col.insert(5);
col.insert(4);
col.insert(1);
col.insert(6);
col.insert(2);
set<int>::const_iterator it;
for(it=col.begin();it!=col.end();++it)
{
cout<<*it<<" ";
}
cout<<endl;
}
在这里我们利用成员函数insert()插入元素,会发现元素不仅自动排列好了顺序,而且我们插入的重复元素并不会重复出现。
如果想使用multiset而不是set,只需要改变容器类型即可,(set和multiset在同一个头文件里)。运行结果如下
- map。 它的元素都是”实值/键值“所形成的一个对组((pair),还记得我之前的文章里提到的pair吗?就是它。)每个元素有一个键,是排序准则的基础,每个键只能出现一次,不允许重复
- Multimap。 它和map相同,但允许重复元素,它可以包含多个键值相同的元素。
下面是一个multimap的例子
#include<iostream>
#include<map>
#include<string>
using namespace std;
int main()
{
multimap<int,string> col;
col.insert(make_pair(5,"tagged"));
col.insert(make_pair(2,"a"));
col.insert(make_pair(1,"this"));
col.insert(make_pair(4,"of"));
col.insert(make_pair(6,"strings"));
col.insert(make_pair(1,"is"));
col.insert(make_pair(3,"multimap"));
multimap<int,string>::iterator it;
for(it=col.begin();it!=col.end();++it);
{
cout<<it->second<<" ";
}
cout<<endl;
}
所有关联式容器都有一个可供选择的template参数,指明排序准则。