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

本文详细探讨了Java中的Arrays.binarySearch()方法,包括其在已排序数组中进行二分查找的原理和使用。当元素存在于数组中时,返回对应的下标;存在多个相同元素时,会根据数组长度的奇偶性返回特定下标;当元素不存在,返回负数表示插入位置。通过对源码的分析,解释了返回值的计算方式以及当元素不存在时的判断逻辑。文章还提供了相关算法题和测试用例,帮助读者深入理解该方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、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 的最短子数组

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值