zoukankan      html  css  js  c++  java
  • Arrays的二分查找

      二分查找也称为折半查找,是对有序元素查找的一种算法,在查找的过程中,不断的将搜索长度减半,因此效率不错。Java的JDK提供了二分法查找的算法,使用的方法是Arrays.binarySearch()。binarySearch()方法提供了多种数据类型的二分查找,比如实现了int、float、double、char、byte和Object类型,还提供了对泛型的支持。在JavaAPI手册中提供了接口说明,比如如下方法:

    1 static int binarySearch(long[] a, int fromIndex, int toIndex, long key)
    2 static int binarySearch(long[] a, long key)
    3 static int binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
    4 static int binarySearch(Object[] a, Object key)
    5 static int binarySearch(short[] a, int fromIndex, int toIndex, short key)
    6 static int binarySearch(short[] a, short key)
    7 static <T> int binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)
    8 static <T> int binarySearch(T[] a, T key, Comparator<? super T> c)

      以上是Arrays类中提供的部分关于binanrySearch()方法的定义,对于不同类型来说,基本提供了两种方法,第一种方法需要在调用时提供数组、开始下标、结束下标和查找的值,比如:

    static int binarySearch(long[] a, int fromIndex, int toIndex, long key)

      另外一种查找的方法是提供数组和查找的值即可,比如:

    static int binarySearch(long[] a, long key)

      对于这两种搜索方法,在Java中提供了统一的调用方法,可以查看其代码,在Java的安装目录下找到src.zip文件,该文件是Java的部分源码。将src.zip文件解压缩,在java/util/Arrays.java中可以找到以上两个方法的实现,代码如下:

    1 public static int binarySearch(long[] a, long key) {
    2     return binarySearch0(a, 0, a.length, key);
    3 }
    4 
    5 public static int binarySearch(long[] a, int fromIndex, int toIndex,
    6                                long key) {
    7     rangeCheck(a.length, fromIndex, toIndex);
    8     return binarySearch0(a, fromIndex, toIndex, key);
    9 }

      从代码中可以看到,两个方法最后都调用了binarySearch0()方法,但是在第二个binarySearch()方法中调用了rangeCheck()方法,该方法用于检查数组长度、开始下标和结束下标的正确性,rangeCheck()方法的实现如下:

     1 /**
     2  * Checks that {@code fromIndex} and {@code toIndex} are in
     3  * the range and throws an exception if they aren't.
     4  */
     5 private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
     6     if (fromIndex > toIndex) {
     7         throw new IllegalArgumentException(
     8                 "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
     9     }
    10     if (fromIndex < 0) {
    11         throw new ArrayIndexOutOfBoundsException(fromIndex);
    12     }
    13     if (toIndex > arrayLength) {
    14         throw new ArrayIndexOutOfBoundsException(toIndex);
    15     }
    16 }

      如果调用第一个binarySearch()方法,数组长度、开始下标和结束下标是方法中自行获取的,因此不需要进行rangeCheck(),而调用第二个binarySearch()方法时,数组长度、开始下标和结束下标是调用时外部提供的,因此为了保证正确性进行了rangeCheck()。

      二分法真正的实现是binarySearch0()方法,根据不同的数据类型,binarySearch0()方法也提供了多种重载,这里只看long类型的实现,代码如下:

     1 private static int binarySearch0(long[] a, int fromIndex, int toIndex,
     2                                  long key) {
     3     int low = fromIndex;
     4     int high = toIndex - 1;
     5 
     6     while (low <= high) {
     7         int mid = (low + high) >>> 1;
     8         long midVal = a[mid];
     9 
    10         if (midVal < key)
    11             low = mid + 1;
    12         else if (midVal > key)
    13             high = mid - 1;
    14         else
    15             return mid; // key found
    16     }
    17     return -(low + 1);  // key not found.
    18 }

      二分查找的思路是从有序(从小到大)数组的中间位置开始查找,如果中间位置的数小于查找的目标值,则查找数组中间值右侧的部分,如果中间位置的数大于查找的目标值,则查找数组中间值左侧的部分,如果相等,则返回当前的下标,如果没有找到则返回一个负数。

      除了上面的实现外,还有一种针对泛型的binarySeach()的方法,如下:

    1 static <T> int binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)
    2 static <T> int binarySearch(T[] a, T key, Comparator<? super T> c)

      在上面两个方法的定义中,最后一个参数是一个比较器,比较器的作用是比较两个元素的大小用的,查看以上两个方法的实现,代码如下:

    1 public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
    2     return binarySearch0(a, 0, a.length, key, c);
    3 }
    4 
    5 public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
    6                                    T key, Comparator<? super T> c) {
    7     rangeCheck(a.length, fromIndex, toIndex);
    8     return binarySearch0(a, fromIndex, toIndex, key, c);
    9 }

      以上两个方法同样调用了binarySearch0()方法,该binarySearch0()方法的实现代码如下:

     1 private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
     2                                      T key, Comparator<? super T> c) {
     3     if (c == null) {
     4         return binarySearch0(a, fromIndex, toIndex, key);
     5     }
     6     int low = fromIndex;
     7     int high = toIndex - 1;
     8 
     9     while (low <= high) {
    10         int mid = (low + high) >>> 1;
    11         T midVal = a[mid];
    12         int cmp = c.compare(midVal, key);
    13         if (cmp < 0)
    14             low = mid + 1;
    15         else if (cmp > 0)
    16             high = mid - 1;
    17         else
    18             return mid; // key found
    19     }
    20     return -(low + 1);  // key not found.
    21 }

      观察代码的第12行,c是比较器,该比较器中提供了一个compare()方法用来比较两个元素的大小,如果midVal比key小,compare返回负数,如果midVal比key大,compare返回整数,如果midVal和key相等,compare则返回0。

      以上就是在学习Arrays工具类的使用时,顺便阅读了它的实现,而刚好又能看懂,所以记录在此!


    我的微信公众号:“码农UP2U”

  • 相关阅读:
    iOS开发之JSON格式数据的生成与解析
    Xcode 怎么查看代码总行数
    iOS OC与JS的交互(JavaScriptCore实现)
    Webstorm设置代码提示
    iOS app性能优化的那些事
    pThread多线程demo
    更新UI放在主线程的原因
    iOS小知识点
    上传本地代码及更新代码到GitHub教程
    logstash安装配置
  • 原文地址:https://www.cnblogs.com/tosser/p/8977800.html
Copyright © 2011-2022 走看看