Skip to content

算法Algorithm

二分查找

Binary search

在有序数组中反复排除一半候选区间的查找算法。

形式陈述 ​

设数组 A[0..n) 依某全序非降排列,目标为 x。下标从 0 开始,半开区间 [ℓ,r) 包含 ℓ 而不包含 r。精确查找从 ℓ=0,r=n 出发,只要 ℓ<r 就取

m=ℓ+⌊r−ℓ2⌋.

若 A[m]<x,令 ℓ=m+1;若 A[m]>x,令 r=m;若相等则返回 m。当 ℓ=r 而尚未命中时,返回“不存在”。其循环不变式是:若目标存在,则当前区间仍包含至少一个目标位置。排序保证每次删去的部分不含目标,区间严格缩短保证算法终止。n≥1 时至多比较 ⌊log2⁡n⌋+1 次;空数组直接结束,不需计算 log⁡0。

求分界位置时应换一个明确接口。设 P(0),…,P(n−1) 先假后真,并约定虚拟哨兵 P(n)=真。仍从 [0,n) 出发,但 P(m) 为真时令 r=m,为假时令 ℓ=m+1;终止后返回 ℓ。不变式为“ℓ 之前全假,自 r 起全真”,因此返回值是第一个真位置;若实际位置全假则返回 n。取 P(i)≡A[i]≥x 就得到 lower bound,算法从不读取不存在的 A[n]。

直觉

排序把一次比较从“关于一个元素的信息”升级为“关于一整段的信息”:既然 A[m]<x,那么 A[0..m] 整段都小于 x,一次比较排除一半候选,这正是猜数游戏每问砍半的策略。信息论图像在单调谓词版本中最精确:每次询问 P(m) 只返回真或假一比特,而答案是 n+1 个可能分界位置之一,故最坏至少需要 ⌈log2⁡(n+1)⌉ 次询问,二分达到同一数量级。精确查找时比较 A[m] 与 x 有小于、等于、大于三种结果,不能逐字说成“一次比较只有一比特”;但受有序结构约束的比较决策树仍给出 Θ(log⁡n) 的最坏界,二分同样在渐近意义下最优。

实现时要始终保持同一套区间约定:区间开闭的语义、中点归入哪一半、每步是否严格缩小区间、重复元素时返回哪一个,都应由所选不变式决定。混用闭区间与半开区间的更新式,容易漏掉端点或无法终止。定宽整数下 ℓ+r 还可能溢出,稳妥写法是 m=ℓ+⌊(r−ℓ)/2⌋。

二分查找半开区间收缩示意图
例子与边界

在 [1,3,3,7,9] 中查找 7:ℓ=0,r=5,m=2,A[2]=3<7,故 ℓ=3;m=4,A[4]=9>7,故 r=4;m=3,A[3]=7 命中——三次比较,而逐项扫描最坏需五次。若改问“第一个不小于 3 的位置”,答案是下标 1;其区间依次是 [0,5)→[0,2)→[0,1)→[1,1):两个等于 3 的中点都使右端左移,最后排除 A[0]=1。此时必须改用单调谓词版的不变式;“相等即停”的版本只保证返回某个出现位置,不承诺首个或最后一个。固定中点与比较规则后,它的返回位置仍是确定的。

未排序的数组没有“排除一半”的依据:在 [2,9,4] 中查找 4,中点 A[1]=9>4 会把算法引向左半 [2],与真实位置失之交臂——排序假设一旦缺失,算法安静地给出错误答案而非报错。复杂度结论还依赖 O(1) 随机访问:链表上定位中点还需指针遍历;谨慎复用区间边界可把总指针移动控制为 O(n),却不会得到数组上的 O(log⁡n) 总时间。若键比较特别昂贵,减少比较次数仍可能有用。区间必须每步严格缩小:闭区间写法中若用 m=⌊(ℓ+r)/2⌋ 搭配 ℓ←m,则在 r=ℓ+1 时 m=ℓ、区间原地不动,循环永不终止。

从优化阈值到最优见证明确补足答案二分的两个接口:数值范围 [0,U] 只需 O(log⁡(U+1)) 次判定,但查询编码与判定成本仍收费;得到最优值后,还要通过受该阈值约束的前缀或问题特有自归约,恢复真正达到它的对象。

推论与应用

单调谓词形式把二分从查表扩展为“答案二分”:只要可行性关于参数单调(容量越大越可行之类),就能用对数次可行性判定逼出最优值,这是把判定器升级为优化器的通用手法。连续版本是实数区间上的对分法,依托介值定理逼近方程的根,每步把包围根的区间长度减半。结构化版本是二叉搜索树,把中点比较固化为指针分叉以支持动态插删。而“每次比较至多一比特信息”的计数论证,同样是比较排序下界的核心。

若许多单调判定都依赖同一份更新历史,批量二分把各自中点按日期分桶,每轮只从初态顺扫重放一次。每条查询仍维持本页的首真边界;共享的是昂贵的判定状态,不是用离线条件替代单调性,也不要求多处理器。

本页的 O(log⁡n) 是有序数组、常数时间随机访问和比较模型下的最坏查询界。前驱问题把“找最后一个不超过 x 的键”提升为可跨模型比较的接口,整数 Word-RAM 能利用键的 bit 结构突破普通比较树路线;分数级联在许多相关有序表之间复用一次定位,把重复二分的成本压到一次对数加线性表数。若数据主要驻留外存,缓存无关搜索树关注的是块传输而非比较次数。三者都从二分的分界思想出发,却改变了问题批次或机器模型。

galloping归并从上一次边界按偏移0、1、3、7、…探测,夹住目标后再运行本页二分。若这次只跨过d项,比较数是O(1+log(d+1)),而非每次都按整个长段长度计费;相等键使用lower还是upper边界,由原左记录必须先出的稳定合同决定。

参考资料
  • Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms, 4th ed., MIT Press, 2022, §2.3 and exercises。

  • Donald E. Knuth, The Art of Computer Programming, Vol. 3: Sorting and Searching, 2nd ed., Addison-Wesley, 1998, §6.2.1。

  • Robert Sedgewick and Kevin Wayne, Algorithms, 4th ed., 2011,§1.1 配套 BinarySearch.java,可与本页半开区间版本对照。

关系图谱18 个相邻概念 · 2 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系