标准模板库(STL)提供了一组表示容器、迭代器、函数对象和算法的模板。STL不是面向对象的编程,而是一种编程模式——泛型编程。
面向对象编程关注的是编程的数据方面,而泛型编程关注的是算法。
容器模板类
STL具有容器概念和容器类型。概念是一种通用类别(如,基本容器、序列容器、关联容器等);容器类型是可用于创建具体容器对象的模板。
下面以概念为线索展开
一、基本容器
容器概念指定了所有STL容器类都必须满足一系列要求:
1. 容器是存储其它对象的对象,存储在容器类对象中的对象(内置类型或OOP意义上的对象)必须是同质的。容器类对象过期时,存储在其中的对象也将过期。
2. 存储在容器类对象中的对象必须是可复制构造的和可赋值的(这些作为元素的对象的类必须定义赋值和复制构造函数)。
3. 所有容器都提供了某些特征和操作(但基本容器不能保证其元素都按特定的顺序存储,也不能保证元素的顺序不变)。
二、序列容器
通过添加要求改进基本容器概念。序列是一种重要改进(满足此概念的容器类型有7种),增加的要求如下(有插入、删除等操作):
序列的可选要求
7种容器序列之间的关系:
vector(计算机矢量)
vector<string> words(4); //将woords初始化为4个string类型的矢量
vector提供了自动内存管理功能,模板类型参数指定了使用哪种分配器对象管理内存,默认使用allocator<T>类(T为模板定义的类型),这个类使用new和delete。
支持随机访问,支持以固定时间在矢量尾插入和删除元素。
vector是可反转容器概念的模型,此概念有两个类方法:rbegin()和rend()。
deque(双端队列)
支持随机访问,并且支持以固定时间在deque对象的开始和末尾插入和删除对象。
list(双向链表)
在list对象的任何位置插入和删除元素的时间都是固定的。
vector强调的是快速访问,而list强调的是快速插入和删除。
list也是可反转容器概念的模型。
list不支持数组表示法([ ])和随机访问。
list模板类中包含双向链表的专用成员函数(未注明的复杂度都为线性):
~链表合并:void merge(list<T, Alloc>&x); //合并后x为空
~从链表中删除val的所有实例:void remove(const T & val);
~使用‘<’运算符对链表进行排序:void sort(); //时间复杂度为NlogN
~将链表内容插入到迭代器pos前面:void splice(iterator pos, list<T, Alloc>x); //插入之后x为空
~将连续的相同元素压缩为单个元素:void unique();
queue(队列)
queue模板类是一个适配器,让底层类(deque)展示典型的队列接口。
不允许随机访问队列元素,不允许遍历队列。
queue的使用限制在队列的基本操作上(将元素添加到队尾,从队首删除元素,查看队首和队尾的值,检查元素数目,测试队列是否为空):
bool empty()const;
size_type size()const;
T & front();
T & back();
void push(const T & x);
void pop();
priority_queue
是一个适配器类,默认的底层是vector。支持的操作与queue类似,只是默认将最大元素移到队首。
提供一个可选的构造函数参数:
priority_queue<int> pd1;
priority_queue<int> pd2(greater<int>); //greater<int>是一个预定义的用于比较的函数对象
stack
是一个适配器类,底层类在默认情况下是vector。
stack模板的限制比vector多,不支持随机访问和遍历。
使用限制在使用栈的基本操作上:
~查看栈是否为空:bool empty()const;
~查看元素数目:sizet_type size();
~返回指向栈顶元素的引用:T & top();
~在栈顶部插入x:void pop(const T & x);
~删除栈顶元素:void pop();
三、关联容器
关联容器将值与键关联在一起,是某种树的实现,有比链表更高的访问速度。
对于关联容器X,X::value_type存储了容器的值类型;X::key_type存储了容器的键类型。
关联容器允许插入新元素,但不能指定元素位置(因为关联容器有确定元素访问位置的算法)。
set / multiset
存储在头文件set中,键与值相同,multiset允许集合中存在相同的值。
set模拟了关联、反转、排序、键唯一的概念。
set的第二个模板参数是可选的,指示用来对键进行排序的比较函数或对象(默认使用模板less<>)。
set也有一个将迭代器区间作为参数的构造函数。
集合的标准操作:
~注:以下这些函数并不是方法而是通用函数,使用这些函数的先决条件是容器必须是经过排序的,set对象自动满足这一条件。
~并集:1. set_union(A.begin(), A.end(), B.begin(), B.end(), ostream_iterator< string, char > out(cout, " ") ); //最后一个参数是输出迭代器
2. set_union(A.begin(), A.end(), B.begin(), B.end(), insert_iterator< set<string> > ( C, C.begin() ) ); //将并集插入到C.begin()指示的位置处
~交集:set_intersection();
~差集:set_difference();
~以下为set的方法
~lower_bound(); //将键作为参数,返回指向第一个不小于键参数的迭代器;
~upper_bound(); //将键作为参数,返回指向第一个大于键参数的迭代器。
map / multimap
map是反转和排序的概念模型,但键和值的类型不同。multimap的同一个键可以与多个值关联。
创建multimap对象:
multimap<int, string> codes; //也有第三个可选参数,用于指出对键进行排序的比较函数或对象
STL模板类pair<class T, class U>将键和值存储在一个对象中:
pair<const int, string> item(213, "Los");
code.insert(item); //因为数据是按键排序的,所以不需要指出插入位置。
对于pair对象,可以使用first和second成员来访问其两个部分:
item.first; //返回键
item.second; //返回值
获取multimap对象的信息:
~将键作为参数,返回该键元素的数目:count();
~lower_bound; upper_bound(); //与set相同
~将键作为区间,返回该键所在迭代器区间:equal_range(); //返回的值封装在一个pair对象中,这里的pair模板两个类型参数都是multimap迭代器。
pair< multimap<int string>::iterator, multimap<int string>::iterator > range = code.equal_range(718);