需求:在有序数组 A 内,查找值target
- 如果找到返回索引
- 如果找不到返回 -1
前提 | 给定一个内含 n 个元素的有序数组 A,一个待查值 target |
1 | 设置 i=0,j=n-1 |
2 | 如果 i \gt j,结束查找,没找到 |
3 | 设置 m = (i+j)/2 ,m 为中间索引并向下取整 |
4 | 如果 target < A[m] 设置 j = m - 1,跳到第2步 |
5 | 如果 A[m] < target 设置 i = m + 1,跳到第2步 |
6 | 如果 A[m] = target,结束查找,找到了 |
代码实现基础版
public class search_binary {public static void main(String[] args) {int[] a = {9, 18,21, 28, 32,40,46};int index = search(a, 32);System.out.println("查找结果为:" + index);}public static int search(int[] a, int target) {int i = 0;int j = a.length - 1;while (i <= j) {int m = (i + j) / 2;if (a[m] < target) {//说明要查找的数在右边i = m + 1;} else if (a[m] > target) {j = m - 1;} else {return m;}}return -1;}
}
由于Java中int类型会自动向下取整,因此我们不需要考虑m带小数的情况。
查找过程如下
但是它仍存在一些问题。那就是Integer数值取值问题,m有可能会变为负数,情景再现。
public static void main(String[] args) {int i = 0;int j = Integer.MAX_VALUE;//j表示int类型所能表达的最大数int m = (i + j) / 2;System.out.println(m);//假设目标值在m右侧i = m + 1;m = (i + j) / 2;System.out.println(m);}
1073741823
-536870912
之所以会出现这种问题,是因为m的值超出了int所能表达的最大值。在计算机中,一个数字最后都会由二进制表示,而int类型能表达的范围是-2147483648~2147483647,最大值转化为二级制为
可以看到第一位数字为0,这是因为Java中,是需要把二进制数字中的第一位数字当作符号位的(0为正,1为负)。超过最大值的二进制表示,第一位就会变为1,在Java中自然会被识别成一个负数。为了避免这个问题,我们可以采用右移运算,也就是将所有的二进制右移一位(相当于除以2)。具体代码实现如下
public static int binarySearch(int[] a, int target) {int i = 0, j = a.length - 1;while (i <= j) {int m = (i + j) >>> 1;if (target < a[m]) { // 在左边j = m - 1;} else if (a[m] < target) { // 在右边i = m + 1;} else {return m;}}return -1;
}
代码实现改动版
public static int binarySearch(int[] a, int target) {int i = 0, j = a.length;while (i < j) {int m = (i + j) >>> 1;if (target < a[m]) { // 在左边j = m;} else if (a[m] < target) { // 在右边i = m + 1;} else {return m;}}return -1;}
与基础版相比,改动版就是修改了 j 的边界值,将j的下次一次取值变为m。首先我们需要清楚的是,a[m]不是目标值是,下标为m的数字是已经判断过了的,因此可以充当 j 的边界值。
流程如下,我们查找29的下标