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

 static int binarySearch(long[] a, int fromIndex, int toIndex, long key)
static int binarySearch(long[] a, long key)
static int binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
static int binarySearch(Object[] a, Object key)
static int binarySearch(short[] a, int fromIndex, int toIndex, short key)
static int binarySearch(short[] a, short key)
static <T> int binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)
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中可以找到以上两个方法的实现,代码如下:

 public static int binarySearch(long[] a, long key) {
return binarySearch0(a, 0, a.length, key);
} public static int binarySearch(long[] a, int fromIndex, int toIndex,
long key) {
rangeCheck(a.length, fromIndex, toIndex);
return binarySearch0(a, fromIndex, toIndex, key);
}

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

 /**
* Checks that {@code fromIndex} and {@code toIndex} are in
* the range and throws an exception if they aren't.
*/
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);
}
}

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

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

 private static int binarySearch0(long[] a, int fromIndex, int toIndex,
long key) {
int low = fromIndex;
int high = toIndex - 1; while (low <= high) {
int mid = (low + high) >>> 1;
long 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.
}

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

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

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

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

 public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
return binarySearch0(a, 0, a.length, key, c);
} public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
T key, Comparator<? super T> c) {
rangeCheck(a.length, fromIndex, toIndex);
return binarySearch0(a, fromIndex, toIndex, key, c);
}

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

 private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
T key, Comparator<? super T> c) {
if (c == null) {
return binarySearch0(a, fromIndex, toIndex, key);
}
int low = fromIndex;
int high = toIndex - 1; while (low <= high) {
int mid = (low + high) >>> 1;
T midVal = a[mid];
int cmp = c.compare(midVal, key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}

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

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


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

Arrays的二分查找的更多相关文章

  1. JAVA基础系列:Arrays.binarySearch二分查找

    首先,binarySearch方法为二分法查找,所以数组必须是有序的或者是用sort()方法排序之后的 1)  binarySearch(Object[] a, Object key) a: 要搜索的 ...

  2. JAVA源码走读(二)二分查找与Arrays类

    给数组赋值:通过fill方法. 对数组排序:通过sort方法,按升序.比较数组:通过equals方法比较数组中元素值是否相等.查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找 ...

  3. 《java入门第一季》之Arrays类前传(排序案例以二分查找注意的问题)

    根据排序算法,可以解决一些小案例.举例如下: /* * 把字符串中的字符进行排序. * 举例:"dacgebf" * 结果:"abcdefg" * * 分析: ...

  4. 零基础学习java------day12------数组高级(选择排序,冒泡排序,二分查找),API(Arrays工具类,包装类,BigInteger等数据类型,Math包)

    0.数组高级 (1)选择排序 它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的起始位置 ...

  5. 二分查找算法java实现

    今天看了一下JDK里面的二分法是实现,觉得有点小问题.二分法的实现有多种今天就给大家分享两种.一种是递归方式的,一种是非递归方式的.先来看看一些基础的东西. 1.算法概念. 二分查找算法也称为折半搜索 ...

  6. Java-数据结构与算法-二分查找法

    1.二分查找法思路:不断缩小范围,直到low <= high 2.代码: package Test; import java.util.Arrays; public class BinarySe ...

  7. page61-将二分查找重写为一段面向对象的程序

    1 将二分查找重写为一段面向对象的程序 (用于在整数集合中进行查找的一种抽象数据类型) public class StaticSETofInts [API] StaticSETofInts(int[] ...

  8. Java学习之二分查找算法

    好久没写算法了.只记得递归方法..结果测试下爆栈了. 思路就是取范围的中间点,判断是不是要找的值,是就输出,不是就与范围的两个临界值比较大小,不断更新临界值直到找到为止,给定的集合一定是有序的. 自己 ...

  9. 二分查找(binary search)

    二分查找又叫折半查找,要查找的前提是检索结果位于已排序的列表中. 概念 在一个已排序的数组seq中,使用二分查找v,假如这个数组的范围是[low...high],我们要的v就在这个范围里.查找的方法是 ...

随机推荐

  1. HTML初识

    HTML初识 web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) so ...

  2. hdu1003 Max Sum---最大子段和+记录开始结束点

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1003 题目大意: 求最大子段和,并且输出最大子段和的起始位置和终止位置. 思路: 根据最大子段和基本 ...

  3. z-index的学习整理转述

    前言:这是笔者第一次写博客,主要是学习之后自己的理解.如果有错误或者疑问的地方,请大家指正,我会持续更新! z-index属性描述元素的堆叠顺序(层级),意思是A元素可以覆盖B元素,但是B元素并没有消 ...

  4. SpringBoot: 配置加载顺序

    在应用程序中各种配置是不可避免的,Spring中对配置的抽象(Environment)可以说是达到了极致,其中有一项尤为突出:PropertySource(配置来源),配置来源通常包括命令行参数,系统 ...

  5. C#之FTP上传下载(一)

    搭建FTP服务器 最近要实现这样一个功能:FTP服务器的上传和下载,搜集了一些资料,在c播客上看到昵称为"傻丫头和科技"的作者写的一篇文章写得挺好,有的地方个人觉得不是很详细,自己 ...

  6. Java多线程之生产者消费者

    生产者和消费者的实例: 商品类:/** * 商品类 * */public class Goods {    final int MAX_NUMBER = 30; // 最大数量    final in ...

  7. kmp——cogs 1570 乌力波

    1570. [POJ3461]乌力波 ★☆   输入文件:oulipo.in   输出文件:oulipo.out   简单对比 时间限制:1 s   内存限制:256 MB [题目描述] 法国作家乔治 ...

  8. 深入理解委托(Delegate)

    前言 委托其实一直以来都感觉自己应该挺熟悉的,直到最近又去翻了翻 CLR via C#,感觉我之前的理解可能还有失偏颇.在这记录一下. 之前文章的链接: 接口和委托的泛型可变性 C#高级编程笔记 De ...

  9. [JSOI2007]文本生成器

    题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版. 该软件可以随机生成一些文章―――总是生成一篇长度 ...

  10. [Noi2016]区间

    题目描述 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一 ...