本文介绍了什么是 STL 以及如何使用 STL 更高效
偷懒地解题。本篇文章将会长期更新,欢迎大家一起监督学习。
1. STL概念
STL(Standard Template Library
,标准模板库),是惠普实验室开发的一系列软件的统称。现主要出现在 C++ 中,STL 从广义上分为:容器(Container
)、算法(Algorithm
)和迭代器(Iterator
)。STL 几乎所有的代码都采用了模板类或者模板函数,这相比传统的由函数和类组成的库来说提供了更好的代码重用机会。
2. STL六大组件
STL 提供了六大组件,彼此之间可以组合套用,这六大组件分别是容器、算法、迭代器、仿函数、适配器、空间配置器。其中,在算法竞赛中用到最多的为容器、算法与迭代器。
- 容器(
Container
):STL 容器为各种数据结构,如vector
、stack
、queue
、map
、set
等,用来存放数据,从实现角度来看,STL 容器是一种class template
。 - 算法(
Algorithm
):STL 的算法多数定义在<algorithm>
头文件中,其中包括了各种常用的算法,如sort
、find
、copy
、reverse
等,从实现角度来看,STL 算法是一种function template
。 - 迭代器(
Iterator
):STL 迭代器扮演了容器与算法之间的胶合剂,共有五种类型,从实现角度来看,迭代器是一种将opetator*
、opetator->
、operator++
等指针相关操作予以重载的class template
。所有 STL 容器都附带有自己专属的迭代器,只有容器的设计者才知道如何遍历自己的元素。 - 仿函数(
Functor
):行为类似函数,可作为算法的某种策略,从实现角度来看,仿函数是一种重载了operator()
的class
或者class template
。 - 适配器(
Adaptor
):一种用来修饰容器或仿函数或迭代器接口的东西。 - 空间配置器(
Allocator
):负责空间的配置与管理。从实现角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template
。
3. STL容器
相信很多人学习 STL 就是为了在比赛中能够更好地装B运用各种数据结构和算法,提高解题速度。确实,使用 STL 中的容器能够不需要自己手写定义各种数据结构,使用 STL 中的算法能够不需要自己手写实现各种基本算法,因此本部分对于算法巨巨们是最为重要的一部分,那么 STL 容器究竟有哪些呢?在做题中该如何使用呢?
3.1 vector
vector
又称变长数组,定义在 <vector>
头文件中,vector
容器是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新的元素。因此 vector
的运用对于内存的合理利用与运用的灵活性有很大的帮助。
vector
的定义方式:
1 | vector<int> v; // 定义一个vector,其中的元素为int类型 |
vector
的常用内置函数:
1 | // vector中的常用内置函数 |
3.2 stack
stack
又称栈,是一种后进先出(Last In First Out,LIFO)的数据结构,定义在 <stack>
头文件中,stack
容器允许新增元素、移除元素、取得栈顶元素,但是除了最顶端以外,没有任何方法可以存取 stack
的其它元素,换言之,stack
不允许有遍历行为。
stack
的定义方式:
1 | stack<int> stk; // 定义一个stack,其中元素的类型为int |
stack
的常用内置函数:
1 | // stack中的常用内置函数 |
3.3 string
string
又称字符串,定义在 <string>
头文件中。C 风格的字符串(以空字符结尾的字符数组)太过复杂难于掌握,因此 C++ 标准库定义了一种 string
类。string
和 vector<char>
在数据结构、内存管理等方面都是相同的。但是,vector<char>
只是单纯的一个“char
元素的容器”,而 string
不仅是一个“char
元素的容器”,它还扩展了一些针对字符串的操作,例如 string
可以使用 c_str()
函数转换为 C 风格的字符串,vector
中并未对输入输出流操作符进行重载,因此无法直接对 vector<char>
进行 cin
或者 cout
这样的操作,但是 string
可以,且 vector<char>
并不能直接实现字符串的拼接,但是 string
可以,string
中重载了 +, +=
运算符。
string
的定义方式:
1 | string str; // 定义一个空的字符串 |
string
的常用内置函数:
1 | // string中的常用内置函数 |
string
的erase()
与remove()
函数的用法:
1 | // string中erase()与remove()的用法 |
3.4 queue/priority_queue
queue
又称队列,是一种先进先出(First In First Out,FIFO)的数据结构,定义在 <queue>
头文件中,queue
容器允许从一端(称为队尾)新增元素(入队),从另一端(称为队头)移除元素(出队)。
priority_queue
又称优先队列,同样定义在 <queue>
头文件中,与 queue
不同的地方在于我们可以自定义其中数据的优先级,优先级高的排在队列前面,优先出队。priority_queue
具有 queue
的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它的本质是用堆实现的,因此可分为小根堆与大根堆,小根堆中较小的元素排在前面,大根堆中较大的元素排在前面。(创建 priority_queue
时默认是大根堆!)
queue/priority_queue
的定义方式:
1 | queue<int> que; // 定义一个queue,其中元素的类型为int |
queue/priority_queue
的常用内置函数:
1 | // queue/priority_queue中的常用内置函数 |
3.5 deque
deque
又称双端队列,定义在 <deque>
头文件中,vector
容器是单向开口的连续内存空间,deque
则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector
也可以在头尾两端插入元素,但是在其头部进行插入操作效率很低。deque
和 vector
最大的差异一是在于 deque
允许使用常数项时间在头部进行元素的插入和删除操作,二是在于 deque
没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。
deque
的定义方式:
1 | deque<int> deq; // 定义一个deque,其中的元素为int类型 |
deque
的常用内置函数:
1 | //deque中的常用内置函数 |
3.6 map/multimap
map/multimap
又称映射,定义在 <map>
头文件中,map
和 multimap
的底层实现机制都是红黑树。map
的功能是能够将任意类型的元素映射到另一个任意类型的元素上,并且所有的元素都会根据元素的键值自动排序。map
所有的元素都是 pair
,同时拥有键值和实值(即 (key, value)
对),key
被视为键值,value
被视为实值,map
不允许两个元素有相同的键值。multimap
和 map
的操作类似,唯一区别是 multimap
的键值允许重复。
map/multimap
的定义方式:
1 | map<string, int> mp; // 定义一个将string映射成int的map |
map/multimap
的常用内置函数:
1 | // map/multimap中的常用内置函数 |
3.7 set/multiset
set/multiset
又称集合,定义在 <set>
头文件中。set
的特性是所有元素都会根据元素的键值自动被排序,set
的元素不像 map
那样可以同时拥有键值和实值,set
的元素既是键值又是实值,set
不允许两个元素有相同的键值,因此总结来说就是 set
中的元素是有序且不重复的。multiset
的特性和用法和 set
完全相同,唯一的区别在于 multiset
允许有重复元素,set
和 multiset
的底层实现都是红黑树。
set/multiset
的定义方式:
1 | set<int> st; // 定义一个set,其中的元素类型为int |
set/multiset
的常用内置函数:
1 | // set/multiset中的常用内置函数 |
3.8 unordered_map/unordered_set
unordered_map/unordered_set
分别定义在 <unordered_map>
与 <unordered_set>
头文件中,内部采用的是 hash
表结构,拥有快速检索的功能。与 map/set
相比最大的区别在于 unordered_map/unordered_set
中的元素是无序的,增删改查的时间复杂度为 O(1)
(map/set
增删改查的时间复杂度为 O(logn)
),但是不支持 lower_bound()/upper_bound()
函数。
unordered_map/unordered_set
的定义方式:
1 | unordered_set<int> st; // 定义一个unordered_set,其中的元素类型为int |
unordered_map/unordered_set
的常用内置函数:
1 | // unordered_map/unordered_set中的常用内置函数 |
4. STL算法
C++ 标准库定义了一组泛型算法,之所以称为泛型指的是它们可以操作在多种容器上,不但可以作用于标准库类型,还可以用在内置数组类型甚至其它类型的序列上。泛型算法定义在 <algorithm>
头文件中,标准库还定义了一组泛化的算术算法(Generalized Numeric Algorithm),定义在 <numeric>
头文件中。使用方法如下:
1 |
|