1、STL概论
首先需要了解泛型编程(generic programming)的概念:
将程序写得尽可能通用;
将算法从数据结构中抽象出来,成为通用的;
C++的模板为泛型程序设计奠定了关键的基础。
为了建立数据结构与算法的一套标准,并且降低他们之间的耦合关系,以提高各自的独立性、弹性、交互操作性,诞生了STL。
1.1、STL基本概念
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。虽说它主要表出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
引入STL后,再也不需要我们重新造轮子,而且写出来的代码更加简洁,容易修改,可移植性高。万一STL所提供的容器或者算法不能满足我们的要求,我们也可以实现自己的容器或算法与STL中的其他组件进行交融。
1.2、STL六大组件简介
STL提供了六大组件,彼此之间可以组合套用,这六大组件分别为:容器、算法、迭代器、仿函数、适配器和空间配置器。
- 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据结构,从实现的角度来看,STL容器是一种class template。
- 算法:各种常用算法,如sort、find、copy、for_each。从实现的角度来看STL的算法是一种function template。
- 迭代器:扮演了容器与算法之间的胶合剂,一共有五种类型,从实现的角度来讲迭代器是一种讲operator*、operator->、operator++、operator--、等指针相关操作予以重载的class template。所有的STL容器都附带自己的专属迭代器,只有容器的是设计者知道如何遍历自己的数据。(原生指针也是一种迭代器)
- 仿函数:行为类似函数,可作为算法的某种策略。从实现的角度来看,仿函数是一种重载了operator()的class或者class template。
- 适配器:一种用来修饰容器或者仿函数或者迭代器接口的东西。
- 空间配置器:负责空间的配置与管理。从实现的角度看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template。
STL六大组件的交互关系:
- 容器通过空间配置器取得数据的存储空间
- 算法通过迭代器获取容器中的内容
- 仿函数可以协助算法完成不同的策略变化
- 适配器可以修饰仿函数
1.3、STL的优点
- 是C++的一部分,无需额外安装
- 将数据与操作分离,数据由容器管理,操作由可定制的算法定义,迭代器则在中间充当“粘合剂”
- 程序员无需考虑STL的内部实现,只需熟练运用即可
- 高重用性,STL中几乎所有的代码都是使用模板类和模板函数实现的
- 高性能,如map可以从海量数据中快速查找出目标数据
- 高移植性:如在项目A上用STL编写的模块,可以直接移植到B上。
2、STL三大组件
2.1容器
STL容器是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组(array)、链表(list)、树(tree)、栈(stack)、队列(queue)、集合(set)、映射表(map),根据数据在容器中的排列特性,可以将其分为序列式容器和关联式容器两种。
- 序列式容器强调值的排列顺序,容器中每个数据都严格按照插入的顺序,如vector、deque、list容器等。
- 关联式容器是儿叉树结构,各个数据之间没有严格的物理顺序关系,也就是说没有保留插入时的顺序。它的特点是在值中选择一个值作为关键字key来索引,方便查找,而另一个关键字value则是真实数据。如Set\multiset容器、map\multimap容器。
2.2算法
以有限的步骤解决逻辑或数学上的问题
- 质变算法:运算过程中更改了容器内数据。例如拷贝,替换,删除等
- 非质变算法:运算过程中没有改变区间的元素内容。例如遍历,计数,寻找极值等
2.3迭代器
迭代器是一个抽象的设计概念,现实程序语言中并没有直接对应这个概念的实物。可理解为:“提供一种方法,使之能够依序寻访某个容器所含的所有元素,而又无需暴漏该容器的内部表示方式。”
认识容器和迭代器简单代码示例
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class Person {
public:
Person(int Age, string Name)
{
this->age = Age; this->name = Name;
}
int age;
string name;
};
void print_inf(Person p) {
cout << p.age<<" "<<p.name<<endl;
}
void test01() {
Person p1=Person(10,"Bob");
Person p2 = Person(20, "Jone");
Person p3 = Person(30, "Tom");
vector<Person>vec;
vec.push_back(p1);
vec.push_back(p2);
vec.push_back(p3);
//第一种遍历vector方法
vector<Person>::iterator vec_begin = vec.begin();
vector<Person>::iterator vec_end = vec.end();
while (vec_begin != vec_end) {
cout <<(*vec_begin).age << " " << (*vec_begin).name << endl;
vec_begin++;
}
//第二种遍历vector方法
for (vector<Person>::iterator it = vec.begin(); it < vec.end(); it++) {
cout<< (*it).age << " " << (*it).name << endl;
}
//第三种遍历vector方法
for_each(vec.begin(), vec.end(), print_inf);
/*for_each源码
template<class _InIt,
class _Fn> inline
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func)
{ // perform function for each element [_First, _Last)
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst)
{
_Func(*_UFirst);
}
return (_Func);
}
*/
}
int main() {
test01();
return 0;
}
参考教程:b站传智教育