算法描述
需求
在有序数组 A 中,查找值 target
- 如果找到返回索引
- 如果找不到返回 -1
前提
给定一个内含 n 个元素的有序数组 A,满足 Ai-1 <= Ai(1 <= i <= n-1),一个待查值 target
算法流程
- 设置 i = 0,j = n-1 为数组 A 的头尾索引
- 如果 i > j,结束查找,没有找到
- 设置 m = floor((i + j) / 2),m 为数组 i 的中间索引,floor 是向下取整( <= (i + j) / 2的最小整数)
- 如果 target < Am,设置 j = m - 1,跳到第二步
- 如果 target > Am,设置 i = m + 1,跳到第二步
- 如果 target = Am,结束查找,找到了
代码实现
public static int binarysearch(int[] a,int target){
int i = 0,j = a.length - 1;//设置指针和初值
while (i <= j){//范围内还有可能的数值
int m = (i + j) >>> 1;//(i + j) / 2中间值
if (target < a[m]){//目标值在左边
j = m - 1;
}
else if (a[m] < target){//目标值在右边
i = m + 1;
}
else {//找到目标值
return m;
}
}
return -1;
}
- i,j 指向的元素也要参与比较,所以循环的条件必须为 i <= j
- (i + j) >>> 1
- ">>>"二进制向右移几位 无符号
- ">>"二进制向右移几位 带符号
- 如果使用 (i + j) / 2,当 i 和 j 过大,运算时会将 (i + j) 的结果(二进制)当作有符号数转换为十进制数,数值大时,符号位为 1,导致 (i + j) 的值为负,而 “>>>” 就避免了这种问题
- 全部都使用 “<” “<=”,符合数组的升序排列,使代码易读,便于修改
性能
时间复杂度
- 最坏情况: O ( l o g n ) O(log~n) O(log n)
- 最好情况:如果待查元素在数组中央,只需要循环一次
O
(
1
)
O(1)
O(1)
空间复杂度 - 需要常数个指针 i , j , m,因此额外占用的空间是 O ( 1 ) O(1) O(1)