1.STL是什么
标准模板库(Standard Template Library,简称STL)简单说,就是一些常用数据结构和算法的模板的集合。
广义上讲,STL分为3类:Algorithm(算法)、Container(容器)和Iterator(迭代器),容器和算法通过迭代器可以进行无缝地连接。
详细的说,STL由6部分组成:容器(Container)、算法(Algorithm)、 迭代器(Iterator)、仿函数(Function object)、适配器(Adaptor)、空间配制器(Allocator)。
2.STL六大组件
-
容器(Container)
是一种数据结构, 如list, vector, 和deques,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器。
-
算法(Algorithm)
是用来操作容器中的数据的模板函数。例如,STL用sort()来对一 个vector中的数据进行排序,用find()来搜索一个list中的对象, 函数本身与他们操作的数据的结构和类型无关,因此他们可以用于从简单数组到高度复杂容器的任何数据结构上。
-
迭代器(Iterator)
提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。 迭代器就如同一个指针。事实上,C++ 的指针也是一种迭代器。 但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符方法的类对象;
-
仿函数(Function object)
仿函数又称之为函数对象, 其实就是重载了操作符的struct,没有什么特别的地方。
-
适配器(Adaptor)
简单的说就是一种接口类,专门用来修改现有类的接口,提供一中新的接口;或调用现有的函数来实现所需要的功能。主要包括3中适配器Container Adaptor、Iterator Adaptor、Function Adaptor。
3.STL中的容器、算法和迭代器
容器:置物之所也
容器可以用于存放各种类型的数据(基本类型的变量,对象等)的数据结构,都是模板类,分为顺序容器、关联式容器、容器适配器三种类型,三种类型容器特性分别如下:
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。例如:vector,deque,list等。
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系。例如:set/multiset,map/multimap
容器适配器:封装了一些基本的容器,使之具备了新的函数功能,比如把deque封装一下变为一个具有stack功能的数据结构。这新得到的数据结构就叫适配器。包含stack,queue,priority_queue。
算法:问题之解法也
有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms),算法分为:质变算法和非质变算法。
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等。
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等。
迭代器:容器和算法之间的粘合剂
Iterator(迭代器)模式又称游标(Cursor)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。 或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。 由于Iterator模式的以上特性:与聚合对象耦合,在一定程度上限制了它的广泛运用,一般仅用于底层聚合支持类,如STL的list、vector、stack等容器类及ostream_iterator等扩展Iterator。
迭代器种类:
种类 | 功能 | 支持运算 |
---|---|---|
输入迭代器 | 对数据的只读访问 | 只读,支持++、==、!= |
输出迭代器 | 对数据的只写访问 | 只写,支持++ |
前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持++、--, |
随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 | 读写,支持++、--、[n]、-n、<、<=、>、>= |
常用的容器中迭代器种类为双向迭代器,和随机访问迭代器。
4.容器算法迭代器初识
vector存放内置数据类型
容器:vector 算法:for_each 迭代器:vector<int>::iterator
代码示例:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
void MyCout(int val)
{
cout << val << endl;
}
void test1()
{
// 创建vector容器
vector<int> v;
v.push_back(5);
v.push_back(8);
v.push_back(11);
v.push_back(9);
v.push_back(6);
vector<int>::iterator vbegin = v.begin();
vector<int>::iterator vend = v.end();
// 第一种遍历方式
for (vector<int>::iterator i = v.begin(); i != v.end(); i++)
{
MyCout;
}
// 第二种遍历方式
for_each(v.begin(), v.end(), MyCout);
}
int main()
{
test1();
return 0;
}
注意:迭代器实际上是指向容器元素的对象,而不是直接的元素值。当你使用
MyCout(i)
时,i
是一个迭代器,而MyCout
需要的是一个int
类型的值。通过*i
可以解引用迭代器,得到它指向的元素值,这样才能正确传递给MyCout
函数。所以MyCout()函数中可以不需要传递参数。