题目描述
Params:a -待查找的升序数组
k -待查找的目标值
Returns:
找到则返回索引
找不到返回-1
1. 刚开始想到的思路 – 直接遍历数组
简单暴力
public static int search(int[] a, int k) {
for (int i = 0;i < a.length;i++) {
if (a[i] == k) {
return i;
}
}
return -1;
}
2.二分查找版-基础版
public static int binarySearchBasic(int[] a,int target){
//设置指针和初值
int i=0,j= a.length-1;
// i~j 范围内有东西
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;
}
演示效果如图:
找到的情况:
找不到的情况:
3.二分查找改进版
public static int binarySearchAlternative(int[] a,int target){
//设置指针和初值 改动第一处
int i=0,j= a.length;
// i~j 范围内有东西 改动第二处
while (i < j) {
//求中间元素m
int m = (i+j) >>> 1;
// 目标在左边
if(target < a[m]) {
//改动第三处
j = m ;
} //目标在右边
else if (a[m] < target) {
i = m + 1;
} //找到
else {
return m;
}
}
return -1;
}
}
演示效果如图
找到的情况:
找不到的情况:
注意点
二分查找只使用于有序数组
①为什么是 i<=j 意味着区间内有未比较的元素, 而不是 i<j ?
i==j它们指向的元素也会参与比较
i<j 只意味着m指向的元素参与比较
②:(i+j) / 2 有没有问题? 相对于基础版和改进版的改动
换成 无符号右移运算符 >>> 右移一位
代码演示如下:
public static void main(String[] args) {
int i = 0;
int j = Integer.MAX_VALUE - 1;
int m = (i+j) / 2;
// System.out.println(m);
i = m + 1;
System.out.println(i); // 1073741824
System.out.println(j); // 2147483646
System.out.println(i+j); //-1073741826
/*
同一个二进制数
1011_1111_1111_1111_1111_1111_1111_1110
不把最高位视为符号位,代表 3221225470
把最高位视为符号位, 代表 -1073741826
*/
m = (i+j) >>> 1;
System.out.println(m); //1610612735
}
此处-1073741826和 3221225470化为二进制数是完全相同的
使用无符号右移运算符 >>> 右移一位 代替 /2 会避免输出 -1073741826
③:都写成小于号有啥好处?
增加可读性