binarysearch可将查找从o(n)降至o(log n),但必须确保数组严格升序,否则结果不可信;需防范nan、类型混排、浮点精度等陷阱,并根据需求选择存在性判断、插入位置或边界查找。

直接用 binarySearch 查已排序数组,能把查找从 O(n) 降到 O(log n),100 万个元素最多查 20 次就出结果。关键不是“会不会写”,而是“怎么用对、用稳、用准”。
必须先确认数组已严格升序
二分查找不校验顺序,错排数组返回结果完全不可信。实际开发中常见陷阱:数组看似有序,实则含 NaN、undefined、字符串数字混排(如 "10" 和 2 比较会出错),或浮点数精度导致的微小逆序。
- 上线前加简单断言:console.assert(arr.every((v, i) => i === 0 || arr[i-1]
- 若数据来自接口或用户输入,排序别省:arr.sort((a, b) => a - b)(数值)或 arr.sort()(纯字符串)
- 注意:JavaScript 中
[10, 2].sort()得到[10, 2],必须传比较函数
正确处理边界与返回值语义
标准 binarySearch 返回索引或 -1,但很多场景需要的是“插入位置”或“首个/末位匹配下标”。比如统计某分数段人数,不能只看是否找到,而要看它在有序成绩数组中的左边界。
- 查存在性:直接判断
result !== -1 - 查插入点(如保持有序插入新元素):当未找到时,
left就是应插入位置(迭代实现中) - 找重复元素首/尾:需改写循环终止条件——例如找左边界时,
right = mid而非mid - 1,并用while (left
避免整数溢出与索引越界
尤其在大型数组(长度接近 2^31)或 C/Java 环境中,(left + right) / 2 可能溢出。JS 虽无整型溢出,但为统一习惯和可移植性,一律用安全写法。
- 中间点计算统一写成:const mid = left + Math.floor((right - left) / 2)
- 初始化
right必须是arr.length - 1(闭区间 [left, right])或arr.length(左闭右开 [left, right)),二者逻辑不同,不能混用 - 循环条件必须匹配区间定义:
left 对应闭区间,<code>left 对应左闭右开
结合业务场景做轻量封装
不要每次手写 while 循环。针对高频需求封装小函数,既防错又提效。
- 查是否存在且返回布尔:
function exists(arr, t) { return binarySearch(arr, t) >= 0; } - 查大于等于目标的最小元素索引(lowerBound):
function lowerBound(arr, t) { /* 返回首个 ≥t 的下标,超界则返回 arr.length */ } - 批量查多个值时,避免重复计算:先排序查询值,再双指针扫描有序数组,比逐个 binarySearch 更快










