算法|二分查找
完成阅读您将会了解二分查找的:
- 算法思想
- 实现步骤
- 实践范例(C++/Rust)
1. 算法思想
二分查找(Binary Search)是二分(Bisection)思想的经典应用,其概念最早在1946年由 John William Mauchly 在摩尔学院讲座中提出,后基本成型于 Derrick Henry Lehmer 在1960年发表在 Teaching combinatorial tricks to a computer [1]中的通用长度的二分查找算法。
二分查找需要在有序序列的基础上进行,每次比较中间元素,根据比较结果更新左右边界,直至成功找到目标元素或查找空间限缩至空,如图1[2],时间复杂度\(O(\lg n)\),空间复杂度\(\Theta(1)\)。

尽管二分查找的基本思想相对简单,但细节可以令人难以招架 ... ——Donald Ervin Knuth [3]
此处引用高纳德(Donald Ervin Knuth)这句话是因为二分查找看似简单的背后,存在令人不易察觉的边界细节以及大规模数据时中间位置计算时产生的整数溢出问题。这些在过去令不少人头疼过。本文将从位运算(Bit Operation)的层面防止较大整数边界计算中心时的溢出问题,具体细节见实践范例。
2. 实现步骤
- 比较中间元素与目标元素;
- 如果目标元素更大,则将左边界提升至当前中心;
- 如果目标元素更小,则将右边界降低至当前中心;
- 如果未寻到目标元素,重复以上过程直至找到目标元素或查找空间限缩至空。
3. 实践范例(C++/Rust)
问题描述:
给定升序序列S,查找目标t。如果t在S中,返回t的位置p,否则返回-1。
输入:S,t
输出:p或-1
解答思路:
运用二分查找算法寻找目标元素。
伪代码1:二分查找
变量说明:S \(\rightarrow\)有序数组;t\(\rightarrow\)目标元素;left\(\rightarrow\)查找空间左闭边界;right\(\rightarrow\)查找空间右开边界;mid\(\rightarrow\)查找空间中心位置
C++解答:
constexpr auto bisearch(auto S, auto len, auto t) noexcept {
unsigned l = 0, r = len;
auto p = -1;
while (l < r && p < 0) {
auto m = (l & r) + ((l ^ r) >> 1);
S[m] > t ? r = m : S[m] < t ? l = m + 1 : p = m;
}
return p;
}
Rust解答:按Rust风格,用None取代-1
pub fn bisearch<T: std::cmp::PartialOrd>(S: &[T], t: T) -> Option<usize> {
let (mut l, mut r) = (0, S.len());
while l < r {
let m = (l & r) + ((l ^ r) >> 1);
match (S[m] > t) as i8 - (S[m] < t) as i8 {
1 => r = m,
-1 => l = m + 1,
_ => return Some(m)
}
}
return None;
}
4. 自我测试
伪代码实践:
N/A
LeetCode选荐:
让每一天足够精致,期待与您的再次相遇! ^_^

浙公网安备 33010602011771号