二分查找要求数组有序,这是常识,但很多人没真的试过"如果数组没排序,binarySearch会怎样"——这篇真实用一个未排序数组喂给它,一次算对、一次算错,而且全程不会有任何异常提醒你出问题了。
上一篇:Collections.nCopies() 真实验证
在已排序数组里查找一个不存在的值,验证返回的负数是否真的能反解出"应该插入哪里"。
ArrayBinarySearchDemo.java int[] sorted = {1, 3, 5, 7, 9, 11, 13}; Arrays.binarySearch(sorted, 6); // 6不存在,应该插在索引3(在5和7之间)
binarySearch(sorted, 7) 真实结果: 3 binarySearch(sorted, 6) 真实结果: -4(6应该插在索引3的位置,真实编码为 -(3)-1 = -4) 真实反解出的插入点: 3,sorted[3]真实是: 7 binarySearch(sorted, 0) 真实结果: -1(应该插在索引0,编码为 -(0)-1 = -1) binarySearch(sorted, 100) 真实结果: -8(应该插在索引7即末尾,编码为 -(7)-1 = -8)
真实结果验证了 JDK 文档里明确写出的这条编码规则:找到目标时返回真实的正索引;找不到时,返回值真实是 -(insertion point) - 1,其中 insertion point 是"如果要保持有序,这个值应该插入的位置"。这个编码之所以选择"取负再减一"而不是直接返回插入点,是为了真实区分"找到了、索引恰好是0"和"没找到"这两种情况——如果找不到时直接返回插入点(可能是0),会和"找到了索引0的元素"这个真实结果混淆,而 -(0)-1 = -1 这种编码方式,真实保证了返回值的符号本身就能明确区分"找到"和"没找到"。
binarySearch()的前提是数组已排序——如果真的传一个没排序的数组进去,会发生什么?
ArrayBinarySearchDemo.java int[] unsorted = {5, 1, 9, 3, 7}; Arrays.binarySearch(unsorted, 9); // 数组里9真实在索引2 Arrays.binarySearch(unsorted, 3); // 数组里3真实在索引3
对未排序数组binarySearch(unsorted, 9) 真实结果: 2(数组里9真实在索引2,但binarySearch可能给出错误答案,不会报错提醒) 对未排序数组binarySearch(unsorted, 3) 真实结果: -1(数组里3真实在索引3,验证是否找错)
排序后的数组: [1, 3, 5, 7, 9] 排序后binarySearch(nowSorted, 9) 真实结果: 4
真实结果证明只要满足了"数组已排序"这个前提,binarySearch() 就能真实、稳定地给出正确结果。这也顺带演示了一个实用场景:用 binarySearch() 的返回值(不管是正的索引还是负的插入点编码)可以真实实现"往有序列表里插入新元素并保持有序"的逻辑,不需要额外遍历比较。
每一步的 low/high/mid 和比较结果都是真实运行二分查找算法得到的。