algorithm库核心是传入左闭右开迭代器区间[begin(), end())并指定操作;它封装边界与迭代器失效等细节,避免手写循环出错。

直接上手用,别先背函数列表。algorithm 库的核心就两条:给它一对迭代器([first, last)),再告诉它你想干啥——找、排、改、算、判,它就帮你做完。手写循环不是不行,但容易漏边界、错下标、忘迭代器失效,而标准算法把这些细节全封好了。
怎么传参数:永远是 [begin(), end()) 这个左闭右开区间
所有 algorithm 函数都按这个规矩接参数,不是“从哪到哪”,而是“从哪开始、到哪结束(不包含)”。这跟容器的 end() 语义完全一致,也跟 for 循环里常用 i 是一个逻辑。
-
std::sort(v.begin(), v.end())—— 排整个vector;std::sort(v.begin() + 2, v.end() - 1)—— 只排中间一段 - 对 C 风格数组:
int arr[5] = {3,1,4,1,5}; std::reverse(arr, arr + 5);,arr + 5就是“末尾之后一个位置” - 错例:
std::find(v.begin(), v.end() + 1, x)——v.end() + 1是越界指针,行为未定义 - 注意:
std::string、std::vector、std::array都支持随机访问迭代器,能用sort、binary_search;std::list不行,得用list::sort()成员函数
std::find_if 和 std::count_if 是你替代 for 循环最常用的入口
比起 std::find(只比值),find_if 和 count_if 接的是谓词(predicate)——也就是一个返回 bool 的可调用对象,可以是 lambda、函数指针或函数对象。这是把“逻辑”和“遍历”真正解耦的关键。
- 查第一个负数:
auto it = std::find_if(v.begin(), v.end(), [](int x) { return x - 统计偶数个数:
int even_cnt = std::count_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }); - 谓词里别捕获局部地址(比如
[&s]然后用s.c_str()),lambda 生命周期短于算法调用时,容易悬垂 - 如果谓词有副作用(比如修改外部变量),
std::find_if只保证执行到第一个true就停,但std::count_if会全部跑完——别依赖执行次数
去重、删除、替换必须配 erase,std::unique 和 std::remove 不真删
std::unique 和 std::remove 都是“移除-擦除惯用法”(erase–remove idiom)里的前半步:它们把要留下的元素往前挪,返回一个新逻辑终点迭代器,但容器大小不变、后面元素还留着。不接 erase,等于白干。
立即学习“C++免费学习笔记(深入)”;
- 正确写法:
auto new_end = std::unique(v.begin(), v.end()); v.erase(new_end, v.end()); - 错例:
std::unique(v.begin(), v.end());—— 看似调用了,但返回值丢弃,v 里还是原样(只是前面排好了,后面是脏数据) -
std::remove按值删,std::remove_if按条件删;它们不保证保留相对顺序?不,它们保持剩余元素的原始顺序 - 别对
std::list用std::remove—— 它有更高效的成员函数list::remove()和list::remove_if()
二分查找前必须先排好序,lower_bound 和 upper_bound 别记反
std::lower_bound 和 std::upper_bound 要求输入区间已按同一规则升序(或自定义比较规则)排列,否则结果无意义。它们返回的是迭代器,不是 bool,也不是下标。
-
std::lower_bound(first, last, val)→ 第一个>= val的位置 -
std::upper_bound(first, last, val)→ 第一个> val的位置 - 两者差值就是
val在有序序列中出现的次数:std::upper_bound(...) - std::lower_bound(...) - 想只判断存不存在?用
std::binary_search(first, last, val),它内部就是调这两个,但只返回bool - 排序和查找用的比较函数必须一致,比如
sort(v.begin(), v.end(), std::greater<int>())</int>后,就得用lower_bound(v.begin(), v.end(), val, std::greater<int>())</int>
最难绷的其实是“以为自己在用算法,其实还在手动管理迭代器边界”。只要记住:所有 algorithm 函数只认迭代器范围,不认容器类型;所有“移除类”函数都不动 size;所有二分类函数都不检查是否已排序——这些不是缺陷,是设计契约。签了约,它才敢给你性能和确定性。


















