二分查找的右边界应设为数组长度减1(即最后一个有效索引),而非数组长度本身;否则在搜索不存在的较大值时,将因越界访问引发arrayindexoutofboundsexception。
二分查找的右边界应设为数组长度减1(即最后一个有效索引),而非数组长度本身;否则在搜索不存在的较大值时,将因越界访问引发arrayindexoutofboundsexception。
二分查找的核心前提之一是:搜索区间必须始终落在合法的数组索引范围内。在基于闭区间 [start, end] 实现的二分查找中(如题中代码),start 和 end 均代表有效的数组下标。Java 数组索引从 0 开始,长度为 n 的数组,其合法下标范围严格为 0 到 n−1(含端点)。因此,初始 end 必须设为 numbers.length - 1 —— 这是最后一个元素的确切位置。
若错误地将 end 初始化为 numbers.length(例如数组长度为 10 时设 end = 10),虽然在某些幸运场景下(如目标值恰好位于前半段且提前命中)看似“能运行”,但算法逻辑已隐含越界风险。我们来看关键问题所在:
当 end = numbers.length 时,循环中计算 mid = (start + end) / 2 可能产生超出范围的索引。例如,对数组 numbers = {1,2,4,6,8,10,12,14,18,20}(长度 10),若设 end = 10,并搜索 key = 24(大于所有元素):
- 初始:start = 0, end = 10 → mid = 5 → numbers[5] = 10
- 后续迭代可能进入:start = 9, end = 10 → mid = (9+10)/2 = 9 → 仍合法
- 但继续:start = 10, end = 10 → mid = 10 → numbers[10] 触发 ArrayIndexOutOfBoundsException
这是因为 numbers[10] 访问了第 11 个位置,而数组仅有索引 0–9。
✅ 正确做法(推荐闭区间实现):
public static int binarySearch(int[] arr, int key) {
int start = 0;
int end = arr.length - 1; // 关键:指向最后一个有效索引
while (start <= end) {
int mid = start + (end - start) / 2; // 推荐写法,避免整型溢出
if (arr[mid] == key) {
return mid;
} else if (arr[mid] < key) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return -1;
}⚠️ 注意事项:
- 不要用 end = arr.length:它不是索引,而是长度,直接用作边界会破坏区间语义;
- 推荐 mid = start + (end - start) / 2:替代 (start + end) / 2,防止大索引下整数溢出(虽本例不明显,但属工程最佳实践);
- 若改用左闭右开区间 [start, end),则 end 初始值应为 arr.length,但此时循环条件需改为 start
总结:end = length - 1 不是“惯例”,而是由数组索引定义决定的必然约束。坚守这一原则,才能保证二分查找在任意输入(包括未命中场景)下健壮、可预测、无异常。










