二分查找思路:
1、 规定要查找的值K可能在数组arr内下标区间a,b
2、 计算区间a,b的中间点m
3、 若k<arr[m],将区间缩小为a,m,继续二分查找
4、 若k>arr[m],将区间缩小为m,b,继续二分查找
5、 若k==arr[m],则找到元素位于位置m
难点:边界控制
要注意的点:关于区间的选法
半开半闭区间方便进行操作
比如说:[a,b)+[b,c)=[a,c)是一个无交集,又不改变区间表达格式的操作
b-a=len([a,b))
[a,a)=>empty range
而:[a,b]+[b,c]却不等于[a,c],这中间叠加的交集,难以处理
因此我们选择的区间是[a,b),所以b表示的是数组最右边+1那个数,这样,整个待二分查找区间就包含了数组所有元素。
代码示例:
package com.sise.recursion;
public class BinarySearch {
/*
* 查找某个元素在数组中的下标
* k:待查找元素
* 查到返回下标,查不到返回-1
*/
public int binarySearch(int[] arr,int k) {
int a=0;
int b=arr.length;
//循环不变式
//[a,b)是个有效区间,(a<=b)
//k可能在区间内
while(a<b){
//(a+b)/2可能溢出
// int m=(a+b)/2;
int m=a+(b-a)/2;
//a==b:m=a and m=b(m=b会越界,这样下标m不包含在区间内,要特殊处理,区间为空)
//因此条件排除空区间
//b==a+1:m=a(可以通过循环)
//b==a+2:m=a+1(可以通过循环)
if(k<arr[m]){
//不能取b=m-1,因为是左闭右开区间,所以如果b取m-1的话,
//m-1这个下标对应的数不在下一次查找的区间范围内,会被漏掉
// b=m-1;
b=m;
}else if(k>arr[m]){
//a是有效的下标,所以既然k>arr[m]
//则k不等于arr[m],可以跳过
a=m+1;
}else{
return m;
}
}
return -1;
}
public static void main(String[] args) {
BinarySearch bs=new BinarySearch();
System.out.println(
bs.binarySearch(new int[]{12,10,15,100},15));
System.out.println(
bs.binarySearch(new int[]{12,10,15,100},-2));
System.out.println(
bs.binarySearch(new int[]{12,10,15,100},101));
System.out.println(
bs.binarySearch(new int[]{12,10,15,100},13));
System.out.println("------------");
System.out.println(
bs.binarySearch(new int[]{},13));
System.out.println(
bs.binarySearch(new int[]{12},13));
System.out.println(
bs.binarySearch(new int[]{13},13));
System.out.println("----------");
System.out.println(
bs.binarySearch(new int[]{12,10},10));
System.out.println(
bs.binarySearch(new int[]{12,10},12));
}
}
运行结果: