二分查找end值设置疑问:数组长度还是长度-1?求解析
numbers.length-1的原因 二分查找里end的取值本质对应两种不同的搜索范围定义,end = numbers.length-1是闭区间搜索模式的标准写法,原因主要有这几点:
逻辑更直观
这种写法定义的搜索范围是[start, end],也就是从start到end的所有下标都是有效的数组索引(数组最大合法索引就是length-1)。初始时范围直接覆盖整个数组的所有元素,每一步调整start或end后,新的范围也明确包含所有待排查的候选元素,符合“查找当前范围内所有元素”的直觉。从根源避免数组越界
如果把end设为numbers.length,它本身是一个无效的数组下标(数组下标从0开始)。要是代码里不小心把end当作索引去访问数组(比如计算mid时出错),会直接抛出ArrayIndexOutOfBoundsException。而用length-1的话,start、end、mid始终都是合法索引,从源头减少了这类低级错误的可能。循环条件与边界处理更一致
闭区间模式下,循环条件是start <= end——只要区间里还有元素(哪怕start和end重合,区间里也还有一个元素),就继续查找。如果用end = numbers.length的左闭右开模式(范围是[start, end)),循环条件必须改成start < end,否则会出现越界或死循环。很多新手容易在两种模式的循环条件上搞混,闭区间写法的容错性更高,所以被更多示例采用。
举个反例:如果你的初始写法保留while(start <= end)且end = numbers.length,当搜索到最后,start会走到numbers.length,此时计算mid = (start + end)/2 = numbers.length,访问numbers[mid]就会直接触发数组越界异常,而用length-1就不会出现这种问题。
两种写法本身都能实现二分查找,但end = numbers.length-1的闭区间写法更符合大多数人的思维习惯,出错概率更低,所以成为了主流示例的选择。
内容的提问来源于stack exchange,提问作者10. Siddharth Joshi

