每次排除一半候选范围

若数组已经按同一比较规则排好顺序,比较目标与中间元素后,就能确定只需继续检查左半或右半。算法维护仍有可能包含答案的区间,直到找到目标,或区间收缩到表明不存在相应元素。

正确性来自排序与区间不变量,而不是“总能跳到中间”这一个动作。边界选取与更新还须保证范围持续变小;空数组、只有一个元素,以及目标位于两端之外的情形,都需要遵守同一接口约定。

参考:[1] [2]

相等命中与插入边界不同

出现重复值时,任意一个相等元素、最左相等位置和相等区间之后的位置,是不同结果。Python的bisect_left返回已有相等项之前的插入点,bisect_right返回它们之后的位置,用以维持有序排列。

这些bisect接口主要使用小于比较来划分区间,不调用相等方法直接证明已经找到目标。若程序需要精确查找,还要检查返回位置是否仍在范围内,以及那里的值是否按所需规则相等,不能把任何插入点都当作一次成功命中。

参考:[2]

比较次数与修改成本分别计算

对可按下标快速访问的数组,候选范围反复减半,搜索通常只需O(log n)次比较。若比较需要处理很长的键,或者底层结构不能直接访问中点,完整运行成本还要包含这些工作。

找到插入位置不代表插入本身也是对数时间。Python列表的insort还需要移动元素,整体为O(n)。搜索进行时若其他线程修改同一序列,排序和边界假设可能失效;官方bisect接口因此也不保证这种并发使用的安全性。

参考:[1] [2]