Arrays的二分查找
二分查找也称为折半查找,是对有序元素查找的一种算法,在查找的过程中,不断的将搜索长度减半,因此效率不错。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的二分查找的更多相关文章
- JAVA基础系列:Arrays.binarySearch二分查找
首先,binarySearch方法为二分法查找,所以数组必须是有序的或者是用sort()方法排序之后的 1) binarySearch(Object[] a, Object key) a: 要搜索的 ...
- JAVA源码走读(二)二分查找与Arrays类
给数组赋值:通过fill方法. 对数组排序:通过sort方法,按升序.比较数组:通过equals方法比较数组中元素值是否相等.查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找 ...
- 《java入门第一季》之Arrays类前传(排序案例以二分查找注意的问题)
根据排序算法,可以解决一些小案例.举例如下: /* * 把字符串中的字符进行排序. * 举例:"dacgebf" * 结果:"abcdefg" * * 分析: ...
- 零基础学习java------day12------数组高级(选择排序,冒泡排序,二分查找),API(Arrays工具类,包装类,BigInteger等数据类型,Math包)
0.数组高级 (1)选择排序 它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的起始位置 ...
- 二分查找算法java实现
今天看了一下JDK里面的二分法是实现,觉得有点小问题.二分法的实现有多种今天就给大家分享两种.一种是递归方式的,一种是非递归方式的.先来看看一些基础的东西. 1.算法概念. 二分查找算法也称为折半搜索 ...
- Java-数据结构与算法-二分查找法
1.二分查找法思路:不断缩小范围,直到low <= high 2.代码: package Test; import java.util.Arrays; public class BinarySe ...
- page61-将二分查找重写为一段面向对象的程序
1 将二分查找重写为一段面向对象的程序 (用于在整数集合中进行查找的一种抽象数据类型) public class StaticSETofInts [API] StaticSETofInts(int[] ...
- Java学习之二分查找算法
好久没写算法了.只记得递归方法..结果测试下爆栈了. 思路就是取范围的中间点,判断是不是要找的值,是就输出,不是就与范围的两个临界值比较大小,不断更新临界值直到找到为止,给定的集合一定是有序的. 自己 ...
- 二分查找(binary search)
二分查找又叫折半查找,要查找的前提是检索结果位于已排序的列表中. 概念 在一个已排序的数组seq中,使用二分查找v,假如这个数组的范围是[low...high],我们要的v就在这个范围里.查找的方法是 ...
随机推荐
- awk、变量、运算符、if多分支
awk.变量.运算符.if多分支 awk: 语法 awk [options] 'commands' files option -F 定义字段分隔符,默认的分隔符是连续的空格或制表符 使用option中 ...
- Java-NIO(四):通道(Channel)的原理与获取
通道(Channel): 由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Chann ...
- DIY一个超简单的画图程序
编译环境:VS2017+Easy_X 最近笔者一直在翻阅Easy_X的帮助手册,学习到了一些关于获取鼠标状态消息函数的知识,感觉收获颇大,于是想试验一番,将所学知识运用出来.先补充一下在Easy_X中 ...
- Node.js+Koa开发微信公众号个人笔记(三)响应文本
响应输入文本和响应事件类似,首先对微信服务器发送来的数据的MsgType进行处理,如果是text,说明是文本,接下来可以对文本内容进行处理,比如用户输入了1,可以给用户回复一个文本或者图文或者视频等信 ...
- 基于angularJS搭建的管理系统
前言 angularJS搭建的系统,是一年前用的技术栈,有些地方比较过时,这里只是介绍实现思路 前端架构 工程目录 项目浅析 项目依赖包配置package.json { "name" ...
- js高阶函数应用—函数柯里化和反柯里化
在Lambda演算(一套数理逻辑的形式系统,具体我也没深入研究过)中有个小技巧:假如一个函数只能收一个参数,那么这个函数怎么实现加法呢,因为高阶函数是可以当参数传递和返回值的,所以问题就简化为:写一个 ...
- 规约模式(Specification Pattern)
一.引言 最近在看一个项目的源码时(DDD),对里面的一些设计思想和设计思路有了一些疑问.当看到(Repository层)中使用了 spec.SatisfiedBy() 时,感觉有点懵.于是在项目中搜 ...
- [ZJOI2007]棋盘制作
题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳. 而我们的 ...
- [WC2008]游览计划
[题目描述] 从未来过绍兴的小 D 有幸参加了Winter Camp 2008,他被这座历史名城的秀丽风景所吸引,强烈要求游览绍兴及其周边的所有景点. 主办者将绍兴划分为 N 行M 列(N×M)个方块 ...
- bzoj2237[NCPC2009]Flight Planning 结论题?
2237: [NCPC2009]Flight Planning Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 55 Solved: 27[Submi ...