一、二分法查找的核心原理
二分查找(Binary Search)是一种在有序数组中查找特定元素的高效算法,时间复杂度为O(log n)。其核心思想是"分而治之":通过每次比较将搜索范围减半,直到找到目标值或确定不存在。
1.1 算法基本流程
- 确定数组的初始边界:low=0, high=数组长度-1
- 计算中间位置:mid = low + (high - low)/2
- 比较中间元素与目标值:
- 若相等,返回索引
- 若目标值较小,调整high=mid-1
- 若目标值较大,调整low=mid+1
- 重复步骤2-3直到low>high
二、Java标准实现与问题
public static int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2; // 避免整数溢出
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
2.1 常见陷阱
- 整数溢出问题:mid = (left+right)/2 在极端情况下会溢出
- 边界条件处理:循环终止条件(left <= right) vs (left < right)
- 重复元素处理:返回的索引不一定是第一个/最后一个匹配项
三、高级变体实现
3.1 查找第一个匹配项
public static int firstOccurrence(int[] arr, int target) {
int left = 0, right = arr.length - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] >= target) {
right = mid - 1;
if (arr[mid] == target) result = mid;
} else {
left = mid + 1;
}
}
return result;
}
3.2 查找最后一个匹配项
public static int lastOccurrence(int[] arr, int target) {
int left = 0, right = arr.length - 1;
int result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] <= target) {
left = mid + 1;
if (arr[mid] == target) result = mid;
} else {
right = mid - 1;
}
}
return result;
}
四、性能优化实战
4.1 循环展开技术
通过减少循环次数提升性能:
public static int optimizedBinarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (right - left > 3) {
int mid = left + (right - left) / 2;
if (arr[mid] < target) left = mid + 1;
else right = mid;
}
// 小范围线性搜索
for (int i = left; i <= right; i++) {
if (arr[i] == target) return i;
}
return -1;
}
4.2 内存局部性优化
通过调整访问模式提升缓存命中率:
// 使用位运算代替除法
int mid = (left + right) >>> 1;
// 预计算常用值
final int targetPlusOne = target + 1;
五、实际应用场景
5.1 数据库索引
B+树索引底层使用二分查找定位数据页
5.2 游戏开发
在排序的NPC属性表中快速查找
5.3 金融系统
高频交易中的价格区间查询
六、算法对比测试
测试数据:1000万有序整数
| 方法 | 平均耗时(ns) |
|------|-------------|
| 线性查找 | 12,345,678 |
| 标准二分 | 98 |
| 优化版 | 63 |
七、常见面试题解析
Q:如何在未排序数组中使用二分查找?
A:需要先进行排序(O(nlogn)),仅当多次查询时有优势
Q:二分查找能否用于链表?
A:理论上可以,但随机访问时间复杂度为O(n),实际效率低于线性查找
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。