1. 迭代算法:for_each
核心特性
- 最基础的遍历算法,对区间
[first, last)中的每个元素执行指定操作 - 是非修改性算法(除非操作函数显式修改元素)
- 支持自定义操作(函数指针、函数对象、Lambda 表达式)
- 返回值:C++11 后返回传入的操作函数对象
函数原型
template<class InputIt, class UnaryFunction> UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // 1. 普通函数作为操作 auto print = [](int x) { std::cout << x << " "; }; std::for_each(vec.begin(), vec.end(), print); // 输出:1 2 3 4 5 std::cout << std::endl; // 2. 修改元素(通过引用捕获) std::for_each(vec.begin(), vec.end(), [](int& x) { x *= 2; }); // 现在vec:{2, 4, 6, 8, 10} // 3. 捕获外部变量 int sum = 0; std::for_each(vec.begin(), vec.end(), [&sum](int x) { sum += x; }); std::cout << "总和:" << sum << std::endl; // 输出:30 return 0; }
注意事项
- 与 C++11 范围 for 循环的区别:
for_each可以返回操作函数对象,适合需要累积状态的场景 - 操作函数的参数如果是值传递,无法修改原元素;必须使用引用传递
int& x - 时间复杂度:O (n),遍历一次区间
2. 查找算法
核心特性
- 在区间中查找单个元素或满足条件的元素
- 返回值:找到则返回指向该元素的迭代器;未找到则返回
last迭代器 - 适用于无序区间(有序区间优先使用二分查找,效率更高)
常用函数
| 函数 | 功能 |
|---|
find(first, last, value) | 查找第一个等于value的元素 |
find_if(first, last, pred) | 查找第一个满足谓词pred的元素 |
find_if_not(first, last, pred) | 查找第一个不满足谓词pred的元素(C++11) |
adjacent_find(first, last) | 查找第一对相邻且相等的元素 |
find_first_of(first1, last1, first2, last2) | 查找区间 1 中第一个出现在区间 2 中的元素 |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> vec = {1, 3, 5, 3, 7, 9, 3}; // 1. 查找指定值 auto it1 = std::find(vec.begin(), vec.end(), 3); if (it1 != vec.end()) { std::cout << "找到3,位置:" << it1 - vec.begin() << std::endl; // 输出:1 } // 2. 查找第一个大于5的元素 auto it2 = std::find_if(vec.begin(), vec.end(), [](int x) { return x > 5; }); std::cout << "第一个大于5的元素:" << *it2 << std::endl; // 输出:7 // 3. 查找第一对相邻相等的元素 std::vector<int> vec2 = {1, 2, 2, 3, 3, 3}; auto it3 = std::adjacent_find(vec2.begin(), vec2.end()); std::cout << "第一对相邻相等的元素:" << *it3 << std::endl; // 输出:2 return 0; }
3. 搜索算法
核心特性
- 在区间中查找子序列或连续重复元素
- 与查找算法的区别:查找单个元素 vs 查找多个元素组成的序列
- 返回值:找到则返回子序列起始位置的迭代器;未找到则返回
last
常用函数
| 函数 | 功能 |
|---|
search(first1, last1, first2, last2) | 查找区间 1 中第一个出现的区间 2 子序列 |
find_end(first1, last1, first2, last2) | 查找区间 1 中最后一个出现的区间 2 子序列 |
search_n(first, last, count, value) | 查找连续count个等于value的元素 |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> text = {1, 2, 3, 4, 2, 3, 4, 5}; std::vector<int> pattern = {2, 3, 4}; // 1. 查找第一个子序列 auto it1 = std::search(text.begin(), text.end(), pattern.begin(), pattern.end()); if (it1 != text.end()) { std::cout << "第一个子序列起始位置:" << it1 - text.begin() << std::endl; // 输出:1 } // 2. 查找最后一个子序列 auto it2 = std::find_end(text.begin(), text.end(), pattern.begin(), pattern.end()); std::cout << "最后一个子序列起始位置:" << it2 - text.begin() << std::endl; // 输出:4 // 3. 查找连续3个5 std::vector<int> vec = {1, 5, 5, 5, 2, 5}; auto it3 = std::search_n(vec.begin(), vec.end(), 3, 5); if (it3 != vec.end()) { std::cout << "找到连续3个5,起始位置:" << it3 - vec.begin() << std::endl; // 输出:1 } return 0; }
4. 统计算法
核心特性
- 统计区间中满足条件的元素个数或进行数值累积
- 分为两类:计数类(
<algorithm>)和数值累积类(<numeric>)
常用函数
| 头文件 | 函数 | 功能 |
|---|
<algorithm> | count(first, last, value) | 统计等于value的元素个数 |
<algorithm> | count_if(first, last, pred) | 统计满足谓词pred的元素个数 |
<numeric> | accumulate(first, last, init) | 计算区间元素与初始值init的和 |
<numeric> | accumulate(first, last, init, op) | 使用自定义操作op进行累积 |
用法示例
#include <iostream> #include <vector> #include <algorithm> #include <numeric> int main() { std::vector<int> vec = {1, 2, 3, 4, 5, 3, 3}; // 1. 统计等于3的元素个数 int cnt1 = std::count(vec.begin(), vec.end(), 3); std::cout << "3的个数:" << cnt1 << std::endl; // 输出:3 // 2. 统计偶数个数 int cnt2 = std::count_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; }); std::cout << "偶数个数:" << cnt2 << std::endl; // 输出:2 // 3. 计算总和 int sum = std::accumulate(vec.begin(), vec.end(), 0); std::cout << "总和:" << sum << std::endl; // 输出:21 // 4. 计算乘积 int product = std::accumulate(vec.begin(), vec.end(), 1, std::multiplies<int>()); std::cout << "乘积:" << product << std::endl; // 输出:540 return 0; }
5. 复制或变换算法
核心特性
- 将源区间的元素复制或变换后复制到目标区间
- 要求目标区间有足够的空间,否则使用
back_inserter等插入迭代器 - 变换算法可以对每个元素执行自定义操作
常用函数
| 函数 | 功能 |
|---|
copy(first, last, d_first) | 将区间[first, last)复制到以d_first开头的目标区间 |
copy_if(first, last, d_first, pred) | 只复制满足谓词pred的元素(C++11) |
copy_n(first, n, d_first) | 复制前n个元素(C++11) |
transform(first, last, d_first, unary_op) | 对每个元素执行一元操作unary_op后复制 |
transform(first1, last1, first2, d_first, binary_op) | 对两个区间的元素执行二元操作后复制 |
用法示例
#include <iostream> #include <vector> #include <algorithm> #include <iterator> // 用于back_inserter int main() { std::vector<int> src = {1, 2, 3, 4, 5}; std::vector<int> dest; // 1. 复制所有元素(使用back_inserter自动扩容) std::copy(src.begin(), src.end(), std::back_inserter(dest)); // dest:{1, 2, 3, 4, 5} // 2. 复制偶数元素 std::vector<int> even; std::copy_if(src.begin(), src.end(), std::back_inserter(even), [](int x) { return x % 2 == 0; }); // even:{2, 4} // 3. 元素平方变换 std::vector<int> squared; std::transform(src.begin(), src.end(), std::back_inserter(squared), [](int x) { return x * x; }); // squared:{1, 4, 9, 16, 25} // 4. 两个区间元素相加 std::vector<int> a = {1, 2, 3}; std::vector<int> b = {4, 5, 6}; std::vector<int> c; std::transform(a.begin(), a.end(), b.begin(), std::back_inserter(c), std::plus<int>()); // c:{5, 7, 9} return 0; }
6. 填充算法
核心特性
- 用指定值或生成的值填充区间
- 分为两类:固定值填充和生成值填充
常用函数
| 函数 | 功能 |
|---|
fill(first, last, value) | 用value填充区间[first, last) |
fill_n(first, n, value) | 用value填充前n个元素 |
generate(first, last, gen) | 用生成函数gen的返回值填充区间 |
generate_n(first, n, gen) | 用生成函数gen的返回值填充前n个元素 |
用法示例
#include <iostream> #include <vector> #include <algorithm> #include <random> int main() { std::vector<int> vec(5); // 1. 填充固定值 std::fill(vec.begin(), vec.end(), 10); // vec:{10, 10, 10, 10, 10} // 2. 填充前3个元素为0 std::fill_n(vec.begin(), 3, 0); // vec:{0, 0, 0, 10, 10} // 3. 生成随机数填充 std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> dis(1, 100); std::generate(vec.begin(), vec.end(), [&]() { return dis(gen); }); // 示例输出:{42, 17, 89, 3, 56} return 0; }
7. 删除算法
⚠️ 核心注意事项
STL 删除算法不会真正删除容器元素,只是将需要保留的元素移到区间前部,返回新的尾迭代器。必须配合容器的erase方法才能真正释放内存。
常用函数
| 函数 | 功能 |
|---|
remove(first, last, value) | 移除所有等于value的元素 |
remove_if(first, last, pred) | 移除所有满足谓词pred的元素 |
unique(first, last) | 移除相邻重复的元素(需先排序) |
unique(first, last, pred) | 使用自定义谓词判断重复 |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> vec = {1, 3, 2, 3, 4, 3, 5}; // 1. 删除所有等于3的元素 auto new_end1 = std::remove(vec.begin(), vec.end(), 3); // 此时vec:{1, 2, 4, 5, ?, ?, ?}(?为未定义值) vec.erase(new_end1, vec.end()); // 真正删除 // vec:{1, 2, 4, 5} // 2. 删除所有偶数 std::vector<int> vec2 = {1, 2, 3, 4, 5, 6}; auto new_end2 = std::remove_if(vec2.begin(), vec2.end(), [](int x) { return x % 2 == 0; }); vec2.erase(new_end2, vec2.end()); // vec2:{1, 3, 5} // 3. 去重(必须先排序) std::vector<int> vec3 = {1, 2, 2, 3, 3, 3, 4}; std::sort(vec3.begin(), vec3.end()); // 先排序 auto new_end3 = std::unique(vec3.begin(), vec3.end()); vec3.erase(new_end3, vec3.end()); // vec3:{1, 2, 3, 4} return 0; }
8. 排序算法
核心特性
- STL 提供了多种排序算法,适用于不同场景
- 默认使用
<运算符比较,支持自定义比较函数 - 时间复杂度:O (n log n)(主流排序算法)
常用函数
| 函数 | 功能 | 时间复杂度 | 稳定性 |
|---|
sort(first, last) | 对区间进行快速排序(不稳定) | O(n log n) | 不稳定 |
stable_sort(first, last) | 对区间进行归并排序(稳定) | O(n log n) | 稳定 |
partial_sort(first, middle, last) | 对前middle-first个元素排序 | O (n log k)(k 为排序元素个数) | 不稳定 |
nth_element(first, nth, last) | 将第 n 个元素放到正确位置,左边都小于它,右边都大于它 | O(n) | 不稳定 |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> vec = {5, 2, 9, 1, 5, 6}; // 1. 默认升序排序 std::sort(vec.begin(), vec.end()); // vec:{1, 2, 5, 5, 6, 9} // 2. 自定义降序排序 std::sort(vec.begin(), vec.end(), std::greater<int>()); // vec:{9, 6, 5, 5, 2, 1} // 3. 部分排序(前3个元素有序) std::vector<int> vec2 = {5, 2, 9, 1, 5, 6}; std::partial_sort(vec2.begin(), vec2.begin() + 3, vec2.end()); // vec2:{1, 2, 5, 9, 5, 6}(前3个最小的元素有序) // 4. 找第3小的元素(索引从0开始) std::vector<int> vec3 = {5, 2, 9, 1, 5, 6}; std::nth_element(vec3.begin(), vec3.begin() + 2, vec3.end()); std::cout << "第3小的元素:" << vec3[2] << std::endl; // 输出:5 return 0; }
9. 堆操作
核心特性
- STL 实现了大顶堆(默认),即堆顶元素是最大值
- 堆是一种完全二叉树,存储在数组中
- 所有堆操作的时间复杂度均为 O (log n)
常用函数
| 函数 | 功能 |
|---|
make_heap(first, last) | 将区间[first, last)构建成一个堆 |
push_heap(first, last) | 将最后一个元素插入到堆中(需先将元素加到容器末尾) |
pop_heap(first, last) | 将堆顶元素移到区间末尾,剩余元素重新调整为堆 |
sort_heap(first, last) | 将堆转换为有序区间(升序) |
is_heap(first, last) | 判断区间是否是一个堆(C++11) |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> heap = {3, 1, 4, 1, 5, 9, 2, 6}; // 1. 构建大顶堆 std::make_heap(heap.begin(), heap.end()); // 堆顶元素是最大值:9 std::cout << "堆顶元素:" << heap.front() << std::endl; // 输出:9 // 2. 插入元素 heap.push_back(7); // 先加到末尾 std::push_heap(heap.begin(), heap.end()); // 调整为堆 // 现在堆顶还是9 // 3. 删除堆顶元素 std::pop_heap(heap.begin(), heap.end()); // 堆顶移到末尾 heap.pop_back(); // 真正删除 // 新堆顶:7 // 4. 堆排序(升序) std::sort_heap(heap.begin(), heap.end()); // heap:{1, 1, 2, 3, 4, 5, 6, 7} return 0; }
10. 二分查找算法
核心特性
- 要求区间必须是有序的(默认升序)
- 时间复杂度:O (log n),远快于线性查找的 O (n)
- 适用于大规模有序数据的查找
常用函数
| 函数 | 功能 | 返回值 |
|---|
binary_search(first, last, value) | 判断value是否存在于区间中 | bool |
lower_bound(first, last, value) | 查找第一个大于等于value的元素 | 迭代器 |
upper_bound(first, last, value) | 查找第一个大于value的元素 | 迭代器 |
equal_range(first, last, value) | 返回等于value的元素区间 | pair <迭代器,迭代器> |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> vec = {1, 2, 3, 4, 4, 4, 5, 6}; // 1. 判断元素是否存在 bool exists = std::binary_search(vec.begin(), vec.end(), 4); std::cout << "4是否存在:" << std::boolalpha << exists << std::endl; // 输出:true // 2. 查找第一个大于等于4的元素 auto it_low = std::lower_bound(vec.begin(), vec.end(), 4); std::cout << "第一个>=4的元素位置:" << it_low - vec.begin() << std::endl; // 输出:3 // 3. 查找第一个大于4的元素 auto it_high = std::upper_bound(vec.begin(), vec.end(), 4); std::cout << "第一个>4的元素位置:" << it_high - vec.begin() << std::endl; // 输出:6 // 4. 统计等于4的元素个数 int cnt = it_high - it_low; std::cout << "4的个数:" << cnt << std::endl; // 输出:3 return 0; }
11. 交换算法
核心特性
- 交换两个元素或两个区间的元素
- 是 STL 中最基础的算法之一,被其他算法广泛调用
常用函数
| 函数 | 功能 |
|---|
swap(a, b) | 交换两个对象a和b的值 |
iter_swap(it1, it2) | 交换两个迭代器it1和it2指向的元素 |
swap_ranges(first1, last1, first2) | 交换两个区间的元素 |
用法示例
#include <iostream> #include <vector> #include <algorithm> int main() { // 1. 交换两个变量 int a = 10, b = 20; std::swap(a, b); std::cout << "a=" << a << ", b=" << b << std::endl; // 输出:a=20, b=10 // 2. 交换两个迭代器指向的元素 std::vector<int> vec = {1, 2, 3, 4}; std::iter_swap(vec.begin(), vec.end() - 1); // vec:{4, 2, 3, 1} // 3. 交换两个区间的元素 std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2 = {4, 5, 6}; std::swap_ranges(vec1.begin(), vec1.end(), vec2.begin()); // vec1:{4, 5, 6}, vec2:{1, 2, 3} return 0; }