0%

二分查找源码解析

之前一篇文章中已经解过一道 leetcode 二分查找的题目了,这篇文章再来分析一下 java 类库中提供的二分查找源码。

对应的类为 java.util.Arrays,方法名为 binarySearch。

1

可以看到:

  • 贴心的提供了所有类型数组的二分查找方法
  • 每种类型都提供了两种二分查找方法:
    • 两个参数(最后一个三个参数):从整个数组中查找
    • 四个参数(倒数第二个五个参数):从数组指定的范围中查找,中间的两个参数指定范围,该范围为前闭后开

每种类型数组的两种二分查找方法底层调用的都是同一个叫做 binarySearch0 的私有方法,因此 binarySearch0 也对应提供了不同类型的方法。binarySearch0 支持从数组指定的范围中查找,同样,中间的两个参数用来指定范围,该范围为前闭后开。

int[]

这部分主要以 int 类型数组的二分查找源码为例,来看看是怎么写的。

  1. 先来看两个参数的 binarySearch 方法。可以看到底层调用 binarySearch0 方法,中间两个参数是 0 和 a.length,即从数组 a 的 [0, a.length) 范围中查找目标值 key。

  1. 再来看四个参数的 binarySearch 方法。可以看到底层同样调用 binarySearch0 方法,中间两个参数是 fromIndex 和 toIndex,即从数组 a 的 [fromIndex, toIndex) 范围中查找目标值 key。

但是在调用 binarySearch0 方法之前,会调用 rangeCheck 方法来检查 fromIndex 和 toIndex 的合法性,不合法则抛出异常。

关于这两个参数的合法性,下面截图中方法注释的 @throws 部分写的非常明白(良心博主,翻译都安排的明明白白),不再赘述。

检查 fromIndex 和 toIndex 合法性的代码也非常简单。

  1. 最后来看 binarySearch0 方法,会发现,代码几乎和之前 leetcode 二分查找那篇文章中我们写的一样,唯一的区别是:如果没找到目标值 key 时的返回值。

关于这点,上面截图中方法注释的 @return 部分也写的非常明白,不再赘述。

关于没找到目标值 key 时为什么返回的是 -(插入点) - 1 的证明方法,在这里也共享出一个链接以供大家阅读:

https://blog.csdn.net/paralysed/article/details/106583034

3

其它类型数组的二分查找源码和 int 类型的大同小异,这部分来具体看看。

  1. byte[]、char[]、long[]、short[] 和 int[] 一样,大小比较用的都是大于小于的方式

  2. Object[] 大小比较用的是 Comparable.compareTo 方法

  1. T[] 的大小比较,最后一个参数可以传自定义比较器,如果没传,则默认走的是 Object[] 的二分查找方法

  1. float[] 和 double[] 的大小比较方法和前面类型的都有一点点不一样。不过还好,我们已经了解了 IEEE 754 标准,并且在上一篇一起分析过 Float.java 和 Double.java 的源码,所以,直接上代码(该部分代码对应其 compare 方法源码)


欢迎关注我的其它发布渠道