STL概述
C++ STL(Standard Template Library,标准模板库)是C++中一个强大且广泛使用的库,包含了大量可复用的模板类和函数。这些工具为程序员提供了非常高效的容器、算法和迭代器,能够帮助开发者快速完成各种常见的编程任务。
STL的主要组成部分可以分为以下三大类:
- 容器(Containers)
- 算法(Algorithms)
- 迭代器(Iterators)
1. 容器(Containers)
STL中的容器是用于存储和管理数据的模板类。容器根据不同的需求,可以分为序列式容器、关联式容器和无序容器。
序列式容器(Sequence Containers)
这些容器存储的元素是按顺序排列的,常见的序列式容器有:
vector
:动态数组,支持快速的随机访问,插入和删除操作相对慢。std::vector<int> vec = {1, 2, 3}; vec.push_back(4); // 添加元素 vec[0] = 5; // 随机访问
deque
:双端队列,支持快速的头尾插入和删除操作,同时也支持随机访问。std::deque<int> dq = {1, 2, 3}; dq.push_front(0); // 在前面插入 dq.push_back(4); // 在后面插入
list
:双向链表,支持在任意位置高效地插入和删除操作,不支持随机访问。std::list<int> lst = {1, 2, 3}; lst.push_back(4); // 尾部插入 lst.push_front(0); // 头部插入
关联式容器(Associative Containers)
关联式容器通过键来管理数据,数据自动按照一定顺序排列(通常是按键的大小顺序)。
set
:存储不重复的元素,数据自动有序排列。std::set<int> s = {3, 1, 2}; s.insert(4); // 插入元素
map
:存储键值对,每个键都是唯一的,数据根据键有序排列。std::map<int, std::string> m; m[1] = "One"; m[2] = "Two";
multiset
和multimap
:允许存储重复的键或元素。unordered_set
:存储不重复的元素,使用哈希表实现。-
无序容器(Unordered Containers)
这些容器基于哈希表实现,数据存储顺序与元素的插入顺序无关,查找和插入的时间复杂度平均为O(1)。
unordered_set
:存储不重复的元素,使用哈希表实现。
std::unordered_set<int> us = {1, 2, 3};
us.insert(4); // 插入元素
unordered_map
:存储键值对,使用哈希表实现。
std::unordered_map<int, std::string> um;
um[1] = "One";
um[2] = "Two";
2. 算法(Algorithms)
STL提供了大量的常用算法,它们大部分是以函数模板的形式实现的,能够对任何符合要求的容器和迭代器进行操作。常见的算法可以分为以下几类:
1. 非修改算法
这些算法不会改变容器中的元素,它们通常用于查询、统计、排序等操作。
std::find
:在范围内查找某个元素。
std::vector<int> vec = {1, 2, 3, 4, 5};
auto it = std::find(vec.begin(), vec.end(), 3);
std::count
:统计某个值在范围中出现的次数。
int count = std::count(vec.begin(), vec.end(), 3);
2. 修改算法
这些算法会改变容器的内容,通常是添加、删除、修改元素。
迭代器的操作
迭代器通常通过begin()
和end()
函数获取。常用的迭代器操作包括:
std::sort
:对范围内的元素进行排序。std::sort(vec.begin(), vec.end());
std::reverse
:对范围内的元素进行反转。std::reverse(vec.begin(), vec.end());
3. 删除算法
std::remove
:移除容器中与给定值相等的元素。该算法实际上不直接删除元素,而是将目标元素移动到末尾。vec.erase(std::remove(vec.begin(), vec.end(), 3), vec.end());
4. 其他常用算法
std::accumulate
:求和、积累结果。int sum = std::accumulate(vec.begin(), vec.end(), 0);
std::transform
:将一个操作应用到每个元素上,并将结果存储到另一个范围。std::vector<int> result(vec.size()); std::transform(vec.begin(), vec.end(), result.begin(), [](int x) { return x * 2; });
3. 迭代器(Iterators)
迭代器是用来遍历容器中元素的工具,它提供了类似指针的操作方式。C++ STL中的大多数容器都支持迭代器。迭代器的种类包括:
- 输入迭代器:只能读取元素,如
std::istream_iterator
。 - 输出迭代器:只能写入元素,如
std::ostream_iterator
。 - 前向迭代器:可以单向遍历容器中的元素,如
std::forward_list::iterator
。 *it
:解引用迭代器,访问当前元素。++it
:前进到下一个元素。--it
:后退到上一个元素(仅适用于双向迭代器)。it + n
:移动到距离当前迭代器n
个位置的元素(适用于随机访问迭代器)。- 双向迭代器:可以向前或向后遍历元素,如
std::list::iterator
。 - 随机访问迭代器:可以随机访问元素,如
std::vector::iterator
、std::deque::iterator
。std::vector<int> vec = {1, 2, 3, 4, 5}; for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; // 输出 1 2 3 4 5 }
4. STL适配器
STL还提供了几种容器适配器,它们是基于已有容器构建的特殊容器类型。
stack
:栈,后进先出。std::stack<int> s; s.push(1); s.pop();
queue
:队列,先进先出。std::queue<int> q; q.push(1); q.pop();
priority_queue
:优先队列,元素按优先级顺序排列。std::priority_queue<int> pq; pq.push(10); pq.push(5);
5. STL中的常见陷阱
- 迭代器失效:在某些容器中,如
vector
或deque
,插入或删除元素可能导致迭代器失效,需要注意在修改容器后重新获取迭代器。 - 内存管理:当使用
std::list
或std::map
这样的容器时,插入元素的内存是动态分配的,需留意性能开销和内存使用。
- 双向迭代器:可以向前或向后遍历元素,如