std::lower_bound 前提是数组已排序,否则返回插入点而非查找结果;未排序时应使用 std::find 或 memchr;需检查迭代器是否越界,排序仅需一次,查找复杂度 o(log n)。

用 std::lower_bound 前提是数组已排序
如果数组没排过序,std::lower_bound 返回的迭代器毫无意义——它不找值,只找“插入点”。实际定位失败时,你拿到的可能是个随机位置,甚至越界。必须确认:排序是前提,不是可选项。
常见错误现象:std::lower_bound(arr, arr + n, x) 返回 arr + n(即末尾后一位),但代码直接解引用,触发 segmentation fault。
- 先调用
std::sort(arr, arr + n),且仅需一次(比如初始化阶段) - 后续每次查找都用
std::lower_bound,时间复杂度稳定O(log n) - 查完务必检查返回迭代器是否等于
arr + n,再判断是否真找到了
无序数组只能靠 std::find 或手写循环
别被“优化”带偏:对纯无序大数组,CPU 缓存友好性比算法花招重要得多。std::find 内部就是线性扫描,汇编层面往往比自己写的 for 循环更优(编译器能更好向量化)。
使用场景:日志检索、配置项查找、一次性任务——数据不重复构建索引,也没法预排序。
- 避免在循环里反复调用
std::find查同一组键;考虑提前建std::unordered_map - 若数组元素是 POD 类型且尺寸固定(如
int[1000000]),用memchr找字节值最快,但仅限单字节匹配 - 多线程分段扫描收益有限:L3 缓存争用常抵消并行开销,实测 4 核查 1GB
int数组,加速比通常
用 std::unordered_map 索引时注意内存与哈希冲突
建索引不是免费的。假设数组有 10M 个 int,std::unordered_map<int size_t></int> 实际内存占用常超 200MB——每个桶含指针+控制字,还有空载因子预留空间。
性能影响明显出现在哈希碰撞高时:比如键全是偶数,而 map 默认桶数是 2 的幂,导致大量映射到同余桶,退化成链表遍历。
- 构造时指定合理桶数:
std::unordered_map<int size_t> index(1(约 100 万桶)</int> - 若键范围紧凑(如 ID 在
[0, 500000]),直接用std::vector<size_t></size_t>当索引,O(1) 且零额外开销 - 避免用字符串做 key 查大数组——哈希计算本身开销可能超过线性扫几个 cache line
std::span + std::ranges::find 是 C++20 更安全的写法
裸指针配长度容易出错:arr + n 越界、n 传错、生命周期不一致。C++20 的 std::span 把数据+长度绑死,编译期防部分误用。
示例:std::span<const int> s(arr, n); auto it = std::ranges::find(s, x);</const> —— 不会意外传错长度,且支持容器适配器无缝切换。
- 旧代码迁移到
std::span时,注意它不拥有内存,仍需确保原数组生命周期长于 span -
std::ranges::find对std::span和std::vector行为一致,方便后续替换底层存储 - 别为了用 ranges 强加
std::views::filter:对大数组过滤再找,等价于两遍扫描,反而更慢
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











