Arrays.binarySearch()方法及其源码分析

文章目录

一、Arrays.binarySearch()方法使用

Arrays.binarySearch()方法与其名字一样,是一个二分查找的方法。

通过二分法查找已排序数组,并返回其下标。

方法参数及其返回值如下:

  1. 当元素存在于数组中,则返回对应元素下标

import java.util.Arrays;
public class test1 {
    public static void main(String[] args) {
        int[] sort = new int[]{10,20,30,40,50,60};
        int index = Arrays.binarySearch(sort,20);
        System.out.println("20的下标为:"+index);
    }
}
运行结果:20的下标为:1
  1. 当存在元素且存在多个

public class test1 {
    public static void main(String[] args) {
        //多个20
        int[] sort = new int[]{10,20,20,40,50,60};
        int index = Arrays.binarySearch(sort,20);
        System.out.println("20的下标为:"+index);
        //多个10
        sort = new int[]{10,10,20,40,50,60};
        index = Arrays.binarySearch(sort,10);
        System.out.println("10的下标为:"+index);
    }
}
运行结果:
20的下标为:2
10的下标为:0

为什么查找20与查找10返回的下标一个是后面的,一个是前面的呢?

我只能说与二分查找特性相关,待会放源码时再细说。

  1. 当元素不存在数组中

public class test1 {
    public static void main(String[] args) {
        int[] sort = new int[]{10,20,30,40,50,60};
        int index = Arrays.binarySearch(sort,25);
        System.out.println("25的下标为:"+index);
        index = Arrays.binarySearch(sort,65);
        System.out.println("65的下标为:"+index);
        index = Arrays.binarySearch(sort,-2);
        System.out.println("-2的下标为:"+index);
    }
}
运行结果:
25的下标为:-3
65的下标为:-7
-2的下标为:-1

当不存在时,因20的下标为1,那么25的下标就为2,返回值为 -(2+1)也就是 -3.

而数组中最小值为10下标为0,而-2比10还小,那么下标就为0,返回值 -(0+1) 也就是-1.

为什么?待会细说

二、源码分析

Arrays.binarySearch()方法的两种传参:

    //两个参数
    public static int binarySearch(int[] a, int key) {
        return binarySearch0(a, 0, a.length, key);
    }
    //四个参数
    public static int binarySearch(int[] a, int fromIndex, int toIndex,int key) {
        rangeCheck(a.length, fromIndex, toIndex);
        return binarySearch0(a, fromIndex, toIndex, key);
    }

我们可以看到到最后都会调用binarySearch0(a, fromIndex, toIndex, key)方法。

那我们先不看这个,我们先看**rangeCheck()**里面是怎样的

    private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
        if (fromIndex > toIndex) {
            throw new IllegalArgumentException(
                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
        }
        if (fromIndex < 0) {
            throw new ArrayIndexOutOfBoundsException(fromIndex);
        }
        if (toIndex > arrayLength) {
            throw new ArrayIndexOutOfBoundsException(toIndex);
        }
    }

我们可以看到哈,这就只是一个防止越界的方法,那么关键代码还是在binarySearch0()中:

 private static int binarySearch0(int[] a, int fromIndex, int toIndex,int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

在这里我们可以看到这就是一个二分查找的流程,但是在返回上有点不同

当存在元素时,返回下标mid,不存在则返回 -(low+1)

现在解决第一个问题,当出现重复元素时会取哪个下标

我们先来看图:

从图中我们可以得知:

  • 当数组长度为偶数时,下标为偶数且靠近当前区间中间的元素会优先被查找

  • 当数组长度为奇数时,下标为奇数且靠近当前区间中间的元素会优先被查找

再来看一组测试:

    public static void main(String[] args) {
        System.out.println("当前数组长度为奇数时:");
        int[] sort = new int[]{10,10,30,40,50,60,70};
        int index = Arrays.binarySearch(sort,10);
        System.out.println("10的下标为:"+index);
        sort = new int[]{10,20,20,40,50,60,70};
        index = Arrays.binarySearch(sort,20);
        System.out.println("20的下标为:"+index);
        sort = new int[]{10,20,30,30,50,60,70};
        index = Arrays.binarySearch(sort,30);
        System.out.println("30的下标为:"+index);
        sort = new int[]{10,20,30,40,40,60,70};
        index = Arrays.binarySearch(sort,40);
        System.out.println("40的下标为:"+index);
        sort = new int[]{10,20,30,40,50,50,70};
        index = Arrays.binarySearch(sort,50);
        System.out.println("50的下标为:"+index);
        sort = new int[]{10,20,30,40,40,60,60};
        index = Arrays.binarySearch(sort,60);
        System.out.println("60的下标为:"+index);
        System.out.println("--------------");
        
        System.out.println("当前数组长度为偶数时:");
        sort = new int[]{10,10,30,40,50,60};
        index = Arrays.binarySearch(sort,10);
        System.out.println("10的下标为:"+index);
        sort = new int[]{10,20,20,40,50,60};
        index = Arrays.binarySearch(sort,20);
        System.out.println("20的下标为:"+index);
        sort = new int[]{10,20,30,30,50,60};
        index = Arrays.binarySearch(sort,30);
        System.out.println("30的下标为:"+index);
        sort = new int[]{10,20,30,40,40,60};
        index = Arrays.binarySearch(sort,40);
        System.out.println("40的下标为:"+index);
        sort = new int[]{10,20,30,40,50,50};
        index = Arrays.binarySearch(sort,50);
        System.out.println("50的下标为:"+index);
    }
运行结果:
当前数组长度为奇数时:
10的下标为:1
20的下标为:1
30的下标为:3
40的下标为:3
50的下标为:5
60的下标为:5
.------------------
当前数组长度为偶数时:
10的下标为:0
20的下标为:2
30的下标为:2
40的下标为:4
50的下标为:4

现在我们可以得出结论,

当数组长度为奇数时,数组中有重复元素,Arrays.binarySearch()会优先返回奇数且靠近当前区间中间的下标

当数组长度为偶数时,数组中有重复元素,Arrays.binarySearch()会优先返回偶数且靠近当前区间中间的下标

现在来解决第二个问题,当元素不存在时如何返回下标:

从源码中我们可以知道,当元素不存在时的返回值与low有关:

当要查找的元素比数组中所有的值都小时:

low一直都会是0,直到mid=low且key<sort[mid] ==> hight=mid-1

从而low>hight导致跳出循环,输出结果。

当要查找的元素比数组中所有的值都大时:

right一直都会是0,直到mid=hight且key>sort[mid] ==> low=mid+1

从而low>hight导致跳出循环,输出结果。

当要查找的元素在数组范围内,但不存在时:

例如:

{10,20,30,40,50,60} 查找 ->25

①mid = 2 , sort[mid] = 30 > 25 ==> hight = mid-1. (此时low=0,hight=1)

②mid = 0 , sort[mid] = 10 < 25 ==> low = mid+1 (此时low=1,hight=1)

③mid = 1 , sort[mid] = 20 < 25 ==> low = mid+1 (此时low=2,hight=1 跳出循环)

④返回 -(low+1) 也就是 -(2+1) = -3.

附上用到此方法的算法题:

剑指 Offer II 008. 和大于等于 target 的最短子数组

个人拙见,如有错误,麻烦请指出,谢谢

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值