这篇文章将介绍 C++ 的 ranges 和 Python 的 bisect 在二分查找中的应用与实现,并附上完整示例代码。
二分查找简介
二分查找(Binary Search)是一种高效搜索算法,用于在有序序列中快速定位目标值。它的时间复杂度为 O(log n),比线性搜索快得多。
在现代编程语言中,很多标准库都封装了二分查找逻辑,不必手写算法。例如:
- C++20 提供了
std::ranges系列算法(如ranges::binary_search,ranges::lower_bound等) - Python 提供了
bisect模块(如bisect_left,bisect_right)
一、C++中的 std::ranges
1. 基本概念
std::ranges 是 C++20 引入的新特性,将算法与范围结合,代码更简洁、类型更安全。
常用的二分查找相关函数:
std::ranges::binary_search(range, value):检查value是否存在于有序范围中std::ranges::lower_bound(range, value):返回第一个 不小于value的位置std::ranges::upper_bound(range, value):返回第一个 大于value的位置
注意:这些函数要求范围已按升序排序,否则结果不正确。
2. 示例代码(C++20)
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges> // C++20 ranges 头文件
int main() {
std::vector<int> data = {1, 3, 5, 7, 9, 11, 13};
// 使用 ranges::binary_search 判断值是否存在
if (std::ranges::binary_search(data, 7)) {
std::cout << "Found 7 in data.\n";
} else {
std::cout << "7 not found.\n";
}
// lower_bound:找到第一个 >= 6 的元素位置
auto lb_it = std::ranges::lower_bound(data, 6);
if (lb_it != data.end()) {
std::cout << "Lower bound for 6 is: " << *lb_it << "\n";
} else {
std::cout << "No element >= 6 found.\n";
}
// upper_bound:找到第一个 > 7 的元素
auto ub_it = std::ranges::upper_bound(data, 7);
if (ub_it != data.end()) {
std::cout << "Upper bound for 7 is: " << *ub_it << "\n";
} else {
std::cout << "No element > 7 found.\n";
}
return 0;
}
运行结果:
Found 7 in data.
Lower bound for 6 is: 7
Upper bound for 7 is: 9
二、Python中的 bisect 模块
1. 基本概念
Python 的 bisect 模块提供了二分查找与排序插入位置计算的功能,常用函数:
bisect.bisect_left(a, x):返回x应插入 到列表a中的位置,保持排序,偏向左边bisect.bisect_right(a, x):返回x的插入位置,偏向右边(即在现有 equal 元素后插入)bisect.insort(a, x)/insort_left:直接按排序插入元素
2. 示例代码(Python)
python
import bisect
data = [1, 3, 5, 7, 9, 11, 13]
# 检查元素是否存在(通过 bisect_left)
x = 7
idx = bisect.bisect_left(data, x)
if idx < len(data) and data[idx] == x:
print(f"Found {x} at index {idx}.")
else:
print(f"{x} not found.")
# lower_bound 类似实现
lb_idx = bisect.bisect_left(data, 6)
if lb_idx < len(data):
print(f"Lower bound for 6 is: {data[lb_idx]}")
else:
print("No element >= 6 found.")
# upper_bound 类似实现
ub_idx = bisect.bisect_right(data, 7)
if ub_idx < len(data):
print(f"Upper bound for 7 is: {data[ub_idx]}")
else:
print("No element > 7 found.")
运行结果:
Found 7 at index 3.
Lower bound for 6 is: 7
Upper bound for 7 is: 9
三、C++与Python的对比
| 特性 | C++ ranges |
Python bisect |
|---|---|---|
| 引入版本 | C++20 | Python标准库(一直存在) |
| API命名风格 | binary_search, lower_bound, upper_bound |
bisect_left, bisect_right |
| 是否返回迭代器/索引 | 返回迭代器 | 返回索引 |
| 插入功能 | 需手动使用 vector.insert 等 |
insort 系列直接插入 |
| 性能 | 编译期优化,更高效 | 运行时动态,适合快速原型 |
四、应用场景
- 查找范围内元素的位置
- 求某一值的上下界
- 避免在大数据中手动写二分查找
- 保持有序列表插入新元素
例如:
- 排行榜排名确定
- 时间序列中快速定位某个时间点
- 财务数据中找某个价格区间的交易记录
✅ 总结
在 C++ 中使用 std::ranges 能让二分查找更简洁、类型安全,并支持各种范围类型;在 Python 中,bisect 模块对于保持列表有序和快速检索位置非常方便。两者在概念上类似,但 Python 返回索引,C++ 返回迭代器/布尔值,因此在使用时需要注意差异。