前提:有序数组
时间复杂度:log2n (每次分一半,所以对N求以2为底的对数就是时间复杂度)
注意一点:向右找left = mid+1;向左找right = mid-1;
先举个简单例子:int a[]={1,2,3,4,5,6,7,8,9,10} 查找11.
然后我们按步骤来,来看看都会有哪些情况:
范围:left:左边第一个下标,right:右边最后一个下标
中间数下标:(left+right)/2
第一次:下标范围0,9,中间数下标(0+9)/2= 4,中间数是:5 ,结果:要找的数比5大 ,进入右空间
第二次:下标范围5,9,中间数下标(5+9)/2= 7,中间数是:8 ,结果:要找的数比8大 ,进入右空间
第三次:下标范围8,9,中间数下标(8+9)/2= 8,中间数是:9 ,结果:要找的数比9大 ,进入右空间
第四次:下标范围9,9,中间数下标(9+9)/2= 9,中间数是:10 ,结果:要找的数比10大 ,进入右空间
第五次:下表范围10,9,不符合left<=right,结束。
当然还有一种最简单的结束查找的情况就是,中间数就是我们要找的数,那也结束了。
对了,上面给的数列偶数个,那奇数个呢?
来看看吧,int a[] = {1,2,3,4,5,6,7,8,9} 查找9
第一次:下标范围0,8,中间数下标(0+8)/2=4,中间数是:5,结果:要找的数比5大 ,进入右空间
第二次:下标范围0,8,中间数下标(5+8)/2=6,中间数是:7,结果:要找的数比7大 ,进入右空间
第三次:下标范围7,8,中间数下标(7+8)/2=7,中间数是:8,结果:要找的数比8大 ,进入右空间
第四次:下标范围8,8,中间数下标(8+8)/2=8,中间数是:9,结果:找到结束。
但是,你会发现在查找11的时候其实结果已经非常明显了,我们要找的数很明显已经大于了a数组中最大的数了,但我们还这样查找了一通,是非常不理智的,所以我们可以在查找前先判断一下我们要找的数是不是在我们查找的范围内,也就是和下标为left的数和下标为right的数比较一下,看是不是在范围内。
还有相等优化即第一个元素和最后一个元素相等则返回。
还有先判断第一个和最后一个元素是否为要找元素(个人感觉这个并没有很好)
结束情况:
范围超出,
找到结束,
left>right结束。
最后是我的一个实现(递归和非递归):
测试:所有a[]里面的数据和-1,111数据答案都没错。
import java.util.Scanner;
/**
* Created by 96274 on 2018/11/18.
*/
public class half {
//递归
public static int binarySearch(int t , int left, int right,int a[]){
//System.out.println("left="+left+",right="+right);
if(t>a[right] || t< a[left]){
return -1;
}
if(left<=right){
int mid = (left+right)/2;
if(a[mid] == t)
return mid;
if(t>a[mid]){
return binarySearch(t,mid+1,right,a);
}else{
return binarySearch(t,left,mid-1,a);
}
}
return -1;
}
//非递归
public static int binarySearch(int t ,int a[]){
int left = 0,right = a.length-1;
if(t>a[right] || t< a[left]){
return -1;
}
while(left<=right){
int mid = (left+right)/2;
if(a[mid] == t)
return mid;
if(t>a[mid]){
left = mid+1;
}else{
right = mid-1;
}
}
return -1;
}
public static void main(String[] args){
int a[] = {1,2,3,3,5,6,7,8,9,19,20};
int t ;
while(true){
Scanner sc = new Scanner(System.in);
t = sc.nextInt();
int x = binarySearch(t,a);//binarySearch(t,0,(a.length-1),a);
System.out.println(""+x);
}
}
}
4273

被折叠的 条评论
为什么被折叠?



