二分查找说人话:
在一个升序的数组里面找到一个想找到的值,一般是返回索引即可。
怎么用二分找?
二分二分就是不断除以二得到猜测值来与目标值进行比较,并且寻找的范围也逐渐折半,直到找到目标值。
看图理解!:
看答案是大还是小来选择左边或者右边的查找范围。
上代码:
package binarySearch;
/**
* 二分查找基础版本
* Params: a -待查找的升序数组
* target -待查找的目标值
* Returns: 找到则返回索引
* 找不到则返回-1
*/
public class BinarySearch {
public static int binarySearchBasic(int[] a,int target){
int i = 0, j = a.length-1;//设置指针和初值
while(i<=j){
int m = (i+j)/2;
if(target < a[m]){
j=m-1;
} else if(target>a[m]){
i=m+1;
} else {
return m;
}
}
return -1;
}
}
下面是测试类,还是挺好用的哦!
package binarySearch;
import org.junit.Test;
import org.junit.jupiter.api.DisplayName;
import static binarySearch.BinarySearch.binarySearchBasic;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestBinarySearch {
@Test
@DisplayName("binarySearchBasic 找到")
public void test1(){
int[] a={7,13,21,30,38,44,52,53};
assertEquals(0,binarySearchBasic(a,7));
assertEquals(1,binarySearchBasic(a,13));
assertEquals(2,binarySearchBasic(a,21));
assertEquals(3,binarySearchBasic(a,30));
assertEquals(4,binarySearchBasic(a,38));
assertEquals(5,binarySearchBasic(a,44));
assertEquals(6,binarySearchBasic(a,52));
assertEquals(7,binarySearchBasic(a,53));
}
@Test
@DisplayName("binarySearchBasic 没找到")
public void test2(){
int[] a={7,13,21,30,38,44,52,53};
assertEquals(-1,binarySearchBasic(a,0));
assertEquals(-1,binarySearchBasic(a,9));
assertEquals(-1,binarySearchBasic(a,22));
assertEquals(-1,binarySearchBasic(a,55));
}
}
给个idea代码结构:
改动版效果一样,直到就行没必要用:
书接上回,这次学了二分查找的平衡版,就是时间复杂度更小的版本,相对于基础版本来说。
代码:
//二分查找平衡版 时间复杂度更小
public static int binarySearch2(int[] a,int target){
int i=0,j=a.length;
while(1<j-i){ //这个while循环是为了逐步缩小范围,最后只剩下相等的情况 再比较是否相等
int m=(i+j)>>>2; //>>>是无符号 >>是有符号
if(target<a[m]){
j=m;
}else {
i=m;
}
}
if(a[i]==target){
return i;
}else{
return -1;
}
}
思路:
首先右边指针j指向最后一个地方的下一个,即空,在while循环中是为了一步一步缩小范围,直到i和i相等,最后比较最后的值与目标值是否相等来判断是否找到目标值。
有一个有意思的小测试,使用的是java本身自带的二分查找方法:
使用maven创建java项目,在test中进行测试:
@Test
@DisplayName("binarySearch java版")
public void test3(){
int[] a={2,5,8};
int target=4;
int i= Arrays.binarySearch(a,target); //java自带的二分查找,若没找到则返回应该插入的索引的负数再-1
System.out.println(i);
if(i<0){ //只要找到了肯定是整数 没找到才是负数
int insertIndex=Math.abs(i+1); //插入点索引
int[] b=new int[a.length+1];
System.arraycopy(a,0,b,0,insertIndex);
b[insertIndex]=target;
//五个参数 数组1 起始索引 数组2 起始索引 复制长度
System.arraycopy(a,insertIndex,b,insertIndex+1,a.length-insertIndex);
System.out.println(Arrays.toString(b));
}
}
这个测试的内容是:首先a数组的值为2,5,8 然后想要找到4这个值,但是没有,java自带的二分超找如果没有找到目标值,那么就会返回负的目标值如果要插入的下标再-1,我这个是手动把4插入到a数组了。
补充一下还有时间复杂度的知识:
上面是一些常见的时间复杂度,一般说时间复杂度分为大O时间复杂度,Ω时间复杂度,c他时间复杂度,大O时间复杂度是代表复杂度最高的一种,Ω时间复杂度是代表复杂度最低的一种,c他是既有最高时间复杂度也有最低时间复杂度的,即目标算法的时间复杂度介于两者之间。