引论
Java的util包下,有一个Arrays工具类。其中的binarySearch方法是Java大神写好的二分查找法,小白就直接拿这个来研究二分算法了。
话不多说,上源码:
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
int key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = a[mid];
if (midVal < key) //判断A
low = mid + 1;
else if (midVal > key) //判断B
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
注意:这个方法的前提是,传入的数组是一个升序的数组。
下面是jdk中关于此方法的一些描述:
参数:
a - 要搜索的数组
key - 要搜索的值
返回:
如果它包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。
分析
我们着重来分析这个方法的返回值:
为什么找到的时候返回的是对应索引,找不到的时候返回的是 -(插入点)-1
第一:我们先以数学思维考虑二分法
假如你和你同学在做猜数游戏,按照二分法的思想,在1~100以内猜数。
第一次猜的时候:我们是在1~100这个区间去猜,在这里,low=0,high=100,mid=50按照二分法的思想,我们首先要问:是比50大还是比50小?
…
那么可以想见的是,我们最终猜的值肯定是一个数(这话好像有点脑残);但是,你要注意到这意味着什么:这表明**while循环执行到最后一次,一定有low=high=mid**,理解这一点很重要。
第二:在理解了第一步数学思维的基础上,我们就可以来分析这个方法的返回值了。
根据第一步的分析,给定的值key最后肯定是和中间索引对应的值midVal进行比较的,有三种情况:
1.key=midVal
此时,判断A和判断B均不成立,返回mid(即key在数组中的索引)
2.key > midVal
此时判断A成立,low = mid +1。注意:因为 key > midVal,所以如果要将key按照数组的顺序插入数组的话,那插入点不就是low的后一位吗?即 mid+1,所以,此时的low对应的恰好就是key在数组中的插入点。又因为此时(前面提到过当key和midVal比较时,low=high,但此时low加了1)low>high,所以while循环不再执行,开始执行语句:
return -(low + 1); // key not found.
得到的结果正是:(-(插入点) - 1)
3.key < midVal
参照第二种情况,不再赘述。