上一章实现了二分查找(基础版)的代码,如下:
public class BinarySearch {
public static void main(String[] args) {
//定义一个数组
int[] arr={3,12,21,30,37,45,56,63};
//1.目标值刚好等于中间值
System.out.println(binarySearchBasic(arr, 30)); //3
//2.目标值大于中间值
System.out.println(binarySearchBasic(arr, 56)); //6
//3.目标值小于中间值
System.out.println(binarySearchBasic(arr, 12)); //1
//4.未找到目标值
System.out.println(binarySearchBasic(arr, 50)); //-1
}
/**
*
* @param arr 升序的数组
* @param target 要查找的元素值
* @return
*/
public static int binarySearchBasic(int[] arr,int target){
//设置指针和初始值
int i=0,j=arr.length-1;
//只要在这个范围内就有值可查
//确定中间索引mid
while (i<=j){
int mid=(i+j)/2;
//目标值小于中间值
if (target<arr[mid]){
j=mid-1;
//目标值大于中间值
}else if (target>arr[mid]){
i=mid+1;
}else {
//找到则返回对应的索引
return mid;
}
}
//找不到则返回-1,此时i>j
return -1;
}
}
看这个代码我们可以明显的发现,这个是不平衡的,比如目标值小于中间值,那么他只会执行if这一个循环,但是如果目标值大于中间值,第一个if循环和else if循环都会执行,这样会大大的降低查找的效率,所以将其改善下,代码如下:
package com.xulu.algorithm.binarysearch;
/**
* @Title: BinarySearch
* @Author xulu
* @Package com.xulu.algorithm.binarysearch
* @Date 2023/4/25 16:56
*/
public class BinarySearchBalance {
public static void main(String[] args) {
//定义一个数组
int[] arr={3,11,15,22,28,30};
//1.目标值刚好等于中间值
System.out.println(binarySearchBalance(arr, 22)); //3
//2.目标值大于中间值
System.out.println(binarySearchBalance(arr, 28)); //4
//3.目标值小于中间值
System.out.println(binarySearchBalance(arr, 3)); //0
//4.未找到目标值
System.out.println(binarySearchBalance(arr, 25)); //-1
}
/**
*
* @param arr 升序的数组
* @param target 要查找的元素值
* @return
*/
public static int binarySearchBalance(int[] arr,int target){
//设置指针和初始值
int i=0,j=arr.length;
//只要在这个范围内就有值可查
//确定中间索引mid
while (1<j-i){
int mid=(i+j)/2;
//目标值小于中间值,此时j只代表边界,不代表指向的元素
if (target<arr[mid]){
j=mid;
}else {
//由于没有了相等判断,所以i不能等于m-1,这样可能会错过与中间值相等的目标值
i=mid;
}
}
//跳出循环后,指向if循环
if (arr[i]==target){
return i;
}else {
return -1;
}
}
}
图2-1
图2-2
首先给出一个有序数组A,如图2-1,i仍然等于0,j指向一个不存在的索引,m=3,假设target=3,此时target<A[m],j=m,m=2,如 图2-2所示。
图2-3
因为j指向的一定不是查找目标,不能减一,target仍然小于A[m],j=m,m=1,如图2-3所示。
图2-4
target还是小于A[m],j=m,m=1,如图2-4。
此时循环条件以及不成立,跳出循环,只剩下i指向的元素没有进行比较,执行if循环,如果等于target,则返回对应的索引,不相等则返回-1。
图2-5
假设另一种情况,target=28,target大于A[m],所以执行else循环,i=m=3,j=6,m=4,如图2-5。
图2-6
此时target不小于A[m],执行else循环i=4,j=6,m=5,如图2-6。
图2-7
此时target<A[m],j=m=5,i=4,如图2-7。
循环不成立,跳出循环执行下面的循环,判断唯一范围内i指向的元素是否等于目标值,相等则返回索引,不相等则返回-1。
这样就达到了所有平衡的效果,且大大减少了循环的次数。