C++ STL 标准库
STL(Standard Template Library)是 C++ 标准库的重要组成部分,提供了丰富的容器、算法和迭代器。本章将详细介绍 STL 的核心组件。
STL 概述
STL 包含以下主要组件:
┌─────────────────────────────────────────────────────────┐
│ STL 组件 │
├─────────────────────────────────────────────────────────┤
│ 容器 │ 数据存储结构,如 vector, map, set 等 │
│ 算法 │ 排序、查找、转换等操作 │
│ 迭代器 │ 遍历容器的对象 │
│ 函数对象│ 可调用对象(仿函数) │
│ 适配器 │ 容器、迭代器、函数适配器 │
│ 分配器 │ 内存管理策略 │
└─────────────────────────────────────────────────────────┘
顺序容器
vector(动态数组)
#include <vector>
#include <iostream>
int main() {
// 创建
std::vector<int> v1; // 空向量
std::vector<int> v2(5); // 5个元素,值为0
std::vector<int> v3(5, 10); // 5个元素,值为10
std::vector<int> v4 = {1, 2, 3}; // 初始化列表
// 访问元素
v4.push_back(4); // 末尾添加
v4[0]; // 下标访问(不检查边界)
v4.at(0); // 下标访问(检查边界)
v4.front(); // 第一个元素
v4.back(); // 最后一个元素
// 遍历
for (int x : v4) {
std::cout << x << " ";
}
std::cout << std::endl;
// 大小操作
v4.size(); // 元素个数
v4.empty(); // 是否为空
v4.capacity(); // 容量
// 修改
v4.pop_back(); // 删除末尾
v4.insert(v4.begin() + 1, 99); // 插入
v4.erase(v4.begin() + 1); // 删除
return 0;
}
deque(双端队列)
#include <deque>
int main() {
std::deque<int> d;
// 两端操作
d.push_front(1); // 头部插入
d.push_back(2); // 尾部插入
d.pop_front(); // 头部删除
d.pop_back(); // 尾部删除
// 随机访问(与 vector 相同)
d[0];
d.at(1);
return 0;
}
list(双向链表)
#include <list>
int main() {
std::list<int> lst = {1, 2, 3, 4, 5};
// 链表特有操作
lst.push_front(0); // 头部插入
lst.push_back(6); // 尾部插入
// 在指定位置插入/删除
auto it = lst.begin();
++it; // 指向第二个元素
lst.insert(it, 99); // 在位置插入
// 双向遍历
for (auto it = lst.begin(); it != lst.end(); ++it) {
std::cout << *it << " ";
}
// splice:将另一个链表移动到当前位置
std::list<int> other = {7, 8, 9};
lst.splice(lst.begin(), other); // other 的元素移动到 lst 开头
return 0;
}
array(C++11)
#include <array>
int main() {
// 固定大小数组(栈上分配)
std::array<int, 5> arr = {1, 2, 3, 4, 5};
// 访问
arr[0]; // 不检查边界
arr.at(0); // 检查边界
arr.front(); // 第一个元素
arr.back(); // 最后一个元素
arr.data(); // 原始指针
// 大小
arr.size(); // 5
arr.empty(); // false
// 遍历
for (int x : arr) {
std::cout << x << " ";
}
// 支持迭代器
std::sort(arr.begin(), arr.end());
return 0;
}
关联容器
set(集合)
#include <set>
int main() {
std::set<int> s = {5, 2, 8, 1, 9, 2}; // 自动去重、排序
// 插入
s.insert(3);
s.insert({10, 11, 12});
// 查找
auto it = s.find(5); // 找到返回迭代器
if (it != s.end()) {
std::cout << "Found: " << *it << std::endl;
}
// 检查存在
if (s.count(3)) {
std::cout << "3 exists" << std::endl;
}
// 删除
s.erase(5);
s.erase(s.begin());
// 遍历(有序)
for (int x : s) {
std::cout << x << " ";
}
return 0;
}
multiset(多重集合)
#include <multiset>
int main() {
std::multiset<int> ms = {1, 2, 2, 3, 3, 3};
// 允许重复
ms.insert(2);
ms.insert(2);
// count: 某个值的个数
std::cout << ms.count(2) << std::endl; // 4
// find: 返回第一个匹配的迭代器
auto it = ms.find(2);
// 删除:删除所有匹配的
ms.erase(3); // 删除所有值为 3 的元素
return 0;
}
map(映射)
#include <map>
int main() {
std::map<std::string, int> ages;
// 插入
ages["Alice"] = 25;
ages.insert({"Bob", 30});
ages.insert(std::make_pair("Charlie", 35));
// 访问
std::cout << ages["Alice"] << std::endl; // 25
// ages["David"] 会创建一个新元素!使用 find 检查
auto it = ages.find("Alice");
if (it != ages.end()) {
std::cout << it->first << ": " << it->second << std::endl;
}
// 遍历(按键排序)
for (const auto& [name, age] : ages) {
std::cout << name << " -> " << age << std::endl;
}
// 删除
ages.erase("Bob");
return 0;
}
multimap(多重映射)
#include <multimap>
int main() {
std::multimap<std::string, int> scores;
// 允许一个键对应多个值
scores.insert({"Alice", 90});
scores.insert({"Alice", 95});
scores.insert({"Bob", 88});
// 查找
auto range = scores.equal_range("Alice");
for (auto it = range.first; it != range.second; ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
unordered_set/map(C++11)
#include <unordered_set>
#include <unordered_map>
int main() {
// 无序容器:哈希表实现,查找 O(1)
std::unordered_set<int> us = {3, 1, 4, 1, 5};
std::unordered_map<std::string, int> um;
um["one"] = 1;
um["two"] = 2;
// 遍历(无序)
for (const auto& [key, value] : um) {
std::cout << key << ": " << value << std::endl;
}
return 0;
}
容器适配器
stack(栈)
#include <stack>
int main() {
std::stack<int> s;
s.push(1); // 入栈
s.push(2);
s.push(3);
s.top(); // 查看栈顶
s.pop(); // 出栈
s.empty(); // 是否为空
s.size(); // 大小
return 0;
}
queue(队列)
#include <queue>
int main() {
std::queue<int> q;
q.push(1); // 入队
q.push(2);
q.push(3);
q.front(); // 查看队首
q.back(); // 查看队尾
q.pop(); // 出队
return 0;
}
priority_queue(优先队列)
#include <queue>
int main() {
// 大顶堆(默认)
std::priority_queue<int> pq;
pq.push(3);
pq.push(1);
pq.push(5);
// pq.top() 每次都是最大的
// 小顶堆
std::priority_queue<int, std::vector<int>, std::greater<int>> pq2;
// 自定义比较
struct Node {
int priority;
std::string data;
};
struct cmp {
bool operator()(const Node& a, const Node& b) const {
return a.priority < b.priority; // 大顶堆
}
};
std::priority_queue<Node, std::vector<Node>, cmp> pq3;
return 0;
}
算法
排序算法
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {5, 2, 8, 1, 9};
// sort: 排序(快速排序,平均 O(n log n))
std::sort(v.begin(), v.end()); // 升序
std::sort(v.begin(), v.end(),
[](int a, int b) { return a > b; }); // 降序
// stable_sort: 稳定排序
std::stable_sort(v.begin(), v.end());
// partial_sort: 部分排序
std::partial_sort(v.begin(), v.begin() + 3, v.end()); // 前3个最小
// nth_element: 找到第 n 小的元素
std::nth_element(v.begin(), v.begin() + 2, v.end()); // 第3小的在正确位置
// reverse: 反转
std::reverse(v.begin(), v.end());
// shuffle: 打乱顺序
std::random_device rd;
std::shuffle(v.begin(), v.end(), rd);
return 0;
}
查找算法
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// find: 查找第一个匹配的元素
auto it = std::find(v.begin(), v.end(), 3);
// find_if: 查找满足条件的元素
it = std::find_if(v.begin(), v.end(),
[](int x) { return x > 3; });
// binary_search: 二分查找(需已排序)
bool found = std::binary_search(v.begin(), v.end(), 3);
// lower_bound: 第一个 >= value 的位置
auto lb = std::lower_bound(v.begin(), v.end(), 3);
// upper_bound: 第一个 > value 的位置
auto ub = std::upper_bound(v.begin(), v.end(), 3);
// equal_range: 返回 [lower, upper) 范围
auto range = std::equal_range(v.begin(), v.end(), 3);
return 0;
}
变换算法
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> result(5);
// transform: 对每个元素进行变换
std::transform(v.begin(), v.end(), result.begin(),
[](int x) { return x * 2; });
// result = {2, 4, 6, 8, 10}
// copy: 复制
std::copy(v.begin(), v.end(), result.begin());
// remove: 删除满足条件的元素
v.erase(std::remove_if(v.begin(), v.end(),
[](int x) { return x % 2 == 0; }),
v.end()); // 删除偶数
// replace: 替换
std::replace(v.begin(), v.end(), 3, 30);
// fill: 填充
std::fill(v.begin(), v.end(), 0);
// unique: 去除相邻重复元素
v.erase(std::unique(v.begin(), v.end()), v.end());
return 0;
}
数值算法
#include <numeric>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// accumulate: 求和
int sum = std::accumulate(v.begin(), v.end(), 0);
// inner_product: 内积
int inner = std::inner_product(v.begin(), v.end(), v.begin(), 0);
// partial_sum: 前缀和
std::vector<int> prefix(5);
std::partial_sum(v.begin(), v.end(), prefix.begin());
// prefix = {1, 3, 6, 10, 15}
// iota: 生成递增序列
std::vector<int> iota(5);
std::iota(iota.begin(), iota.end(), 1);
// iota = {1, 2, 3, 4, 5}
return 0;
}
迭代器
迭代器类型
#include <vector>
#include <iterator>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// 前向迭代器
auto it = v.begin();
++it; // 可以递增
// 双向迭代器(list, set, map)
++it;
--it;
// 随机访问迭代器(vector, deque)
auto it2 = v.begin() + 3;
it2 - v.begin(); // 3
*(it2 + 1); // 访问下个元素
// 反向迭代器
std::reverse_iterator<std::vector<int>::iterator> rit;
for (auto rit = v.rbegin(); rit != v.rend(); ++rit) {
std::cout << *rit << " ";
}
// 插入迭代器
std::vector<int> dest;
std::copy(v.begin(), v.end(), std::back_inserter(dest));
return 0;
}
迭代器适配器
#include <iterator>
#include <sstream>
int main() {
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5, 6};
// 反向迭代器
for (auto it = v1.rbegin(); it != v1.rend(); ++it) {
std::cout << *it << " ";
}
// 流迭代器
std::istringstream iss("1 2 3 4 5");
std::vector<int> v;
std::copy(std::istream_iterator<int>(iss),
std::istream_iterator<int>(),
std::back_inserter(v));
// ostream 迭代器
std::copy(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, " "));
// 移动迭代器(C++11)
// std::move(v.begin(), v.end(), dest.begin());
return 0;
}
函数对象
lambda 表达式
#include <algorithm>
#include <functional>
int main() {
auto isEven = [](int x) { return x % 2 == 0; };
std::vector<int> v = {1, 2, 3, 4, 5};
// 查找
auto it = std::find_if(v.begin(), v.end(), isEven);
// 排序
std::sort(v.begin(), v.end(),
[](int a, int b) { return a > b; });
// 使用 std::greater
std::sort(v.begin(), v.end(), std::greater<int>());
return 0;
}
预定义函数对象
#include <functional>
#include <algorithm>
int main() {
// 算术函数对象
std::plus<int> add;
std::cout << add(3, 5) << std::endl; // 8
std::minus<int> sub;
std::multiplies<int> mul;
std::divides<int> div;
std::modulus<int> mod;
std::negate<int> neg;
// 比较函数对象
std::equal_to<int> eq;
std::not_equal_to<int> ne;
std::greater<int> gt;
std::less<int> lt;
std::greater_equal<int> ge;
std::less_equal<int> le;
// 逻辑函数对象
std::logical_and<int> land;
std::logical_or<int> lor;
std::logical_not<int> lnot;
// 使用 bind 绑定参数
auto isGreaterThan5 = std::bind(std::greater<int>(), std::placeholders::_1, 5);
std::cout << isGreaterThan5(10) << std::endl; // true
return 0;
}
练习
- 使用 vector 实现一个学生成绩管理系统
- 使用 map 实现一个单词计数器
- 使用 algorithm 实现各种排序和查找
- 使用 lambda 实现一个事件处理系统
小结
本章学习了:
- 顺序容器:vector、deque、list、array
- 关联容器:set、map、multiset、multimap、unordered_*
- 容器适配器:stack、queue、priority_queue
- 算法:排序、查找、变换、数值算法
- 迭代器:各种迭代器类型和使用
- 函数对象:lambda、预定义函数对象
下一步
接下来让我们学习 C++ 智能指针,了解现代 C++ 的内存管理。