2.二分查找(平衡版)

上一章实现了二分查找(基础版)的代码,如下:

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。

这样就达到了所有平衡的效果,且大大减少了循环的次数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值