二分查找要求list必须有序且支持随机访问,核心是双指针控制边界、中点防溢出计算、三分支收缩,未找到时返回left即插入位置;需避免切片递归、空列表未处理、类型不一致等问题。

在初级项目开发中,用有序 List 实现二分查找,核心是“确保有序 + 控制边界 + 比较收缩”。它不依赖高级框架,几行逻辑就能替代线性遍历,把查找效率从 O(n) 降到 O(log n)。下面直接说实用要点。
前提必须满足:List 真的有序且不可变
二分查找只对已排序的列表有效。常见错误是:
- 插入新元素后没重新排序(比如用
list.append()后直接查) - 误把含重复值但未严格升序的列表当有序(如
[1, 3, 2, 4]) - 用的是 LinkedList 或其他非随机访问结构(Python 的
list支持 O(1) 索引,没问题;Java 的ArrayList可以,LinkedList不推荐)
建议在查找前加一句断言或日志检查:assert lst == sorted(lst)(仅调试期),或封装时注明“调用者需保证输入有序”。
基础循环写法(推荐新手掌握)
用左右双指针控制查找范围,每次比较后舍弃一半:
-
初始化:
left = 0,right = len(lst) - 1 -
循环条件:
while left (闭区间,包含端点) -
取中点防溢出:
mid = left + (right - left) // 2(比(left + right) // 2更安全) -
三种分支:
- 相等 → 直接返回
mid - 目标更小 →
right = mid - 1 - 目标更大 →
left = mid + 1
- 相等 → 直接返回
-
未找到时返回:常规返回
-1;若需插入位置(如题干示例),返回left(即最终左边界,就是应插入处)
实际编码注意点
避免几个初级易错细节:
-
别用切片递归(如
binary_search(lst[mid+1:], target))——会新建子列表,时间/空间开销大,也不利于理解边界逻辑 -
空列表要单独处理:
if not lst: return -1,否则len(lst)-1会是 -1,导致逻辑错乱 -
类型一致:确保
lst元素和target可比(如都是 int,不要混 str 和 int) - 测试用例覆盖边界:查第一个、最后一个、不存在的值(比所有小/比所有大)、空列表、单元素列表
一个可直接粘贴的 Python 示例
支持查找索引,也支持返回插入位置(兼容 LeetCode 风格):
def binary_search_insert_pos(lst, target):if not lst:
return 0
left, right = 0, len(lst) - 1
while left mid = left + (right - left) // 2
if lst[mid] == target:
return mid
elif lst[mid] left = mid + 1
else:
right = mid - 1
return left # 插入位置,也是未找到时的左边界











