来自 http://www.hollischuang.com/archives/1269?

怎样检查一个数组(无序)是否包括一个特定的值?这是一个在Java中经经常使用到的并且非常实用的操作。同一时候,这个问题在Stack Overflow中也是一个非常热门的问题。

在投票比較高的几个答案中给出了几种不同的方法,可是他们的时间复杂度也是各不相同的。本文将分析几种常见使用方法及其时间成本。

检查数组是否包括某个值的方法

使用List

public static boolean useList(String[] arr, String targetValue) {
return Arrays.asList(arr).contains(targetValue);
}

使用Set

public static boolean useSet(String[] arr, String targetValue) {
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
}

使用循环推断

public static boolean useLoop(String[] arr, String targetValue) {
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
}

使用Arrays.binarySearch()

Arrays.binarySearch()方法仅仅能用于有序数组!

!!

假设数组无序的话得到的结果就会非常奇怪。

查找有序数组中是否包括某个值的使用方法例如以下:

public static boolean useArraysBinarySearch(String[] arr, String targetValue) {
int a = Arrays.binarySearch(arr, targetValue);
if(a > 0)
return true;
else
return false;
}

时间复杂度

以下的代码能够大概的得出各种方法的时间成本。

基本思想就是从数组中查找某个值,数组的大小各自是5、1k、10k。

这样的方法得到的结果可能并不精确。可是是最简单清晰的方式。

public static void main(String[] args) {
String[] arr = new String[] { "CD", "BC", "EF", "DE", "AB"}; //use list
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useList(arr, "A");
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("useList: " + duration / 1000000); //use set
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useSet(arr, "A");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useSet: " + duration / 1000000); //use loop
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useLoop(arr, "A");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useLoop: " + duration / 1000000); //use Arrays.binarySearch()
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
useArraysBinarySearch(arr, "A");
}
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("useArrayBinary: " + duration / 1000000);
}

执行结果:

useList:  13
useSet: 72
useLoop: 5
useArraysBinarySearch: 9
使用一个长度为1k的数组 String[] arr = new String[1000]; Random s = new Random();
for(int i=0; i< 1000; i++){
arr[i] = String.valueOf(s.nextInt());
}

结果:

useList:  112
useSet: 2055
useLoop: 99
useArrayBinary: 12

使用一个长度为10k的数组

String[] arr = new String[10000];

Random s = new Random();
for(int i=0; i< 10000; i++){
arr[i] = String.valueOf(s.nextInt());
}

结果:

useList:  1590
useSet: 23819
useLoop: 1526
useArrayBinary: 12

总结

显然。使用一个简单的循环方法比使用不论什么集合都更加高效。很多开发人员为了方便,都使用第一种方法,可是他的效率也相对较低。由于将数组压入Collection类型中,首先要将数组元素遍历一遍,然后再使用集合类做其它操作。

假设使用Arrays.binarySearch()方法。数组必须是已排序的。

由于上面的数组并没有进行排序,所以该方法不可使用。

实际上,假设你须要借助数组或者集合类高效地检查数组中是否包括特定值,一个已排序的列表或树能够做到时间复杂度为O(log(n)),hashset能够达到O(1)。

(英文原文结束,以下是译者注)

使用ArrayUtils

除了以上几种以外。Apache Commons类库中还提供了一个ArrayUtils类,能够使用其contains方法推断数组和值的关系。

import org.apache.commons.lang3.ArrayUtils;
public static boolean useArrayUtils(String[] arr, String targetValue) {
return ArrayUtils.contains(arr,targetValue);
}

相同使用以上几种长度的数组进行測试,得出的结果是该方法的效率介于使用集合和使用循环推断之间(有的时候结果甚至比使用循环要理想)。

useList:  323
useSet: 3028
useLoop: 141
useArrayBinary: 12

useArrayUtils: 181

useList:  3703
useSet: 35183
useLoop: 3218
useArrayBinary: 14
useArrayUtils: 3125

事实上,假设查看ArrayUtils.contains的源代码能够发现,他推断一个元素是否包括在数组中事实上也是使用循环推断的方式。

部分代码例如以下:

    if(array == null) {
return -1;
} else {
if(startIndex < 0) {
startIndex = 0;
} int i;
if(objectToFind == null) {
for(i = startIndex; i < array.length; ++i) {
if(array[i] == null) {
return i;
}
}
} else if(array.getClass().getComponentType().isInstance(objectToFind)) {
for(i = startIndex; i < array.length; ++i) {
if(objectToFind.equals(array[i])) {
return i;
}
}
} return -1;
}

所以,相比較之下,我更倾向于使用ArrayUtils工具类来进行一些合数祖相关的操作。毕竟他能够让我少写非常多代码(由于自己写代码难免有Bug,毕竟apache提供的开源工具类库都是经过无数开发人员考验过的),并且,效率上也并不低太多。

在Java中怎样高效的推断数组中是否包括某个元素的更多相关文章

  1. 在Java中如何高效的判断数组中是否包含某个元素

    原文出处: hollischuang(@Hollis_Chuang) 如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Ove ...

  2. java中如何高效的判断数组中是否包含某个元素---

    package zaLearnpackage; import org.apache.commons.lang3.ArrayUtils; import java.util.Arrays; import ...

  3. 【Java】 剑指offer(51)数组中的逆序对

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成 ...

  4. 【c语言】二维数组中的查找,杨氏矩阵在一个二维数组中,每行都依照从左到右的递增的顺序排序,输入这种一个数组和一个数,推断数组中是否包括这个数

    // 二维数组中的查找,杨氏矩阵在一个二维数组中.每行都依照从左到右的递增的顺序排序. // 每列都依照从上到下递增的顺序排序.请完毕一个函数,输入这种一个数组和一个数.推断数组中是否包括这个数 #i ...

  5. JS中split使用方法和数组中元素的删除

    JS中split使用方法和数组中元素的删除 JS中split使用方法 <script language="javascript"> function spli(){ d ...

  6. Java 高效检查一个数组中是否包含某个值

    如何检查一个数组(未排序)中是否包含某个特定的值?在Java中,这是一个非常有用并又很常用的操作.同时,在StackOverflow中,有时一个得票非常高的问题.在得票比较高的几个回答中,时间复杂度差 ...

  7. 【Java】 剑指offer(39) 数组中出现次数超过一半的数字

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如 ...

  8. 【Java】 剑指offer(53-3) 数组中数值和下标相等的元素

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 假设一个单调递增的数组里的每个元素都是整数并且是唯一的.请编程 ...

  9. 【Java】 剑指offer(56-1) 数组中只出现一次的两个数字

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程 ...

随机推荐

  1. Ubuntu14.04安装配置LAMP环境(php5.6)

    sudo apt-get install python-software-properties sudo apt-get update sudo apt-get install vim sudo ap ...

  2. AC日记——Maximal GCD codeforces 803c

    803C - Maximal GCD 思路: 最大的公约数是n的因数: 然后看范围k<=10^10; 单是答案都会超时: 但是,仔细读题会发现,n必须不小于k*(k+1)/2: 所以,当k不小于 ...

  3. [thinkphp] MD!! 数组构造的好好的,硬是有一个值无法写入数据库

    我都要抓狂了,buildsql()方法又用不了,最后决定看runtime里面的文件.先删掉所有的runtime,然后提交一次,就可以在runtime里面看到对应解析后的文件,这样应该可以知道问题在哪. ...

  4. BZOJ1588 营业额统计 (Splay)

    营业额统计 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额. ...

  5. (转)NSString 类的使用

    官网连接地址:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/Creat ...

  6. linux-系统资源查看-静态

    查看系统版本:lsb_release -a 查看cpu:lscpu 查看内存:free -m          (free -g  单位是GB) 查看硬盘空间情况df -h

  7. Visio中如何画面积一样的形状

    如图,刚开始我想着用辅助的那些线(对齐),实现不了,后来想想直接复制就行了...........

  8. u-boot-2015.01在tq2440上的初步移植

    作者: 彭东林 邮箱: pengdonglin137@163.com QQ:   405728433 开发板:     tq2440 工具:       Win7 + VMware + Debian6 ...

  9. kaptcha验证码

    @Action("/validimg") public String validimg() throws Exception { genernateCaptchaImage(); ...

  10. vs2012 webservice创建

    第一步:打开VS2012,新建空项目,注意选择.NET Framework的版本.这里我选择的是.NET Framework 4 新建好项目后,在项目中添加一个WebService项 打开这个文件,我 ...