std::equal_range 返回 pair 是因为它需表示等于目标值的元素区间[first, second),其中first为lower_bound、second为upper_bound。

std::equal_range 为什么返回 pair 而不是单个迭代器
因为你要找的是「所有等于给定值的元素组成的连续区间」,而有序容器里相同值可能有多个,std::equal_range 返回的是 std::pair<It, It>,其中 first 是第一个不小于目标值的位置(等价于 lower_bound),second 是第一个大于目标值的位置(等价于 upper_bound)。这个区间 [first, second) 就是所有匹配元素的左闭右开范围。
常见错误是误以为它返回“起始和结束索引”,结果用 it->second - it->first 算长度时出错——其实得用 std::distance(it.first, it.second),尤其在非随机访问迭代器(如 std::list)上不能直接相减。
在原生数组上怎么用 std::equal_range
std::equal_range 要求传入迭代器,对 C 风格数组需显式传入指针:用数组名作首地址,加 sizeof(arr)/sizeof(*arr) 得尾后指针。别直接传数组名当迭代器——那会退化为指针但类型不明确,容易触发模板推导失败。
示例:
立即学习“C++免费学习笔记(深入)”;
int arr[] = {1, 2, 2, 2, 3, 4, 4};
size_t n = sizeof(arr) / sizeof(arr[0]);
auto range = std::equal_range(arr, arr + n, 2); // ✅ 正确
// auto range = std::equal_range(std::begin(arr), std::end(arr), 2); // ❌ 编译不过:std::begin(arr) 是 int*,但 std::end(arr) 是 int*+n,类型一致但部分编译器推导失败
- 必须确保数组已排序,否则行为未定义
- 若目标值不存在,
range.first == range.second,此时区间为空 - 使用
std::vector更安全:std::equal_range(v.begin(), v.end(), x)类型推导稳定
自定义比较函数时要注意 operator< 和 comp 的一致性
如果你用自定义 comp(比如降序查找),必须保证它满足严格弱序,且和排序时用的比较逻辑完全一致。否则 equal_range 可能返回错误区间或越界。
例如数组按降序排好:{5, 4, 4, 4, 2, 1},你要查 4:
auto range = std::equal_range(arr, arr + n, 4, std::greater<int>{}); // ✅
// 错误写法:
// auto range = std::equal_range(arr, arr + n, 4); // ❌ 默认升序,结果错乱
- 比较函数类型必须和排序所用的一致,哪怕只差一个
const修饰符都可能编译失败 - lambda 捕获为空时可直接用,但带捕获的 lambda 无法作为模板参数,得用函数对象或
std::function(不推荐,性能差)
std::equal_range 在 vector 和 set 中的性能差异
在 std::vector(底层是数组)上调用 equal_range 是 O(log n),因为二分查找;但在 std::set 上也是 O(log n),虽然它是红黑树——因为 equal_range 对关联容器做了专门重载,不是简单遍历。
但注意:std::set::equal_range 返回的是 std::set::iterator,而 std::vector::equal_range 返回的是 std::vector::iterator,两者解引用行为不同(set 迭代器解引用得 const value_type&)。
- 不要对
std::unordered_set用equal_range——它没实现,编译报错:no matching function for call to 'equal_range' - 如果只是判断存在性,用
count()或find()更直观;equal_range的价值只在你需要全部匹配位置时才体现
真正容易被忽略的是:当目标值重复次数极多(比如百万个相同元素),equal_range 本身仍是 O(log n),但后续遍历区间是 O(k),k 是重复数——这步开销不在算法复杂度里,却可能成为瓶颈。


















