来自 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. JDK7集合框架源码阅读(七) ArrayDeque

    基于版本jdk1.7.0_80 java.util.ArrayDeque 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to li ...

  2. J.U.C并发框架源码阅读(七)CyclicBarrier

    基于版本jdk1.7.0_80 java.util.concurrent.CyclicBarrier 代码如下 /* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is ...

  3. 网络监控工具ntopng

    网络监控工具ntopng   ntopng是Kali提供的一个网络监控软件,用于显示当前网络的使用情况.它能列出当前使用网络的主机,并且显示每台主机发送和接受的数据包.同时,它提供强大的数据处理功能, ...

  4. DQL数据查询语言——连接查询

    --内连接 两种写法 等值连接select r.*,b.bummc from t_hq_ryxx r, t_hq_bm b where r.bumbm = b.bumbm select r.*,b.b ...

  5. 【NOIP模拟赛】【数学真奇妙】【递推】旅行者问题

    旅行者问题 [问题描述] lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行.lahub想去参观n个目的地(都在一条直道上).lahub在起点开始他的旅行.第i个目的地和起 ...

  6. Linux Programmer's Manual --- reboot

    REBOOT(2) Linux Programmer's Manual REBOOT(2) NAME reboot - reboot or enable/disable Ctrl-Alt-Del SY ...

  7. 【hibernate/JPA】对实体类的的多个字段建立唯一索引,达到复合主键的效果【spring boot】注解创建唯一索引和普通索引

    对实体类的的多个字段建立唯一索引,达到复合主键的效果 package com.sxd.swapping.domain; import lombok.Getter; import lombok.Sett ...

  8. DateFormatUtil格式化时间

    package org.xiaowu.json.demo; import java.util.Calendar; import java.util.Date; import org.apache.co ...

  9. JavaScript的filter用法

    Js的有些操作会改变原来的对象:有些操作则不会改变原来对象. 数组的filter方法就不会改变原来数组 利用filter,可以巧妙地去除Array的重复元素: 'use strict'; var r, ...

  10. 控制流程完整性:给大家介绍一种“另类”的Javascript反分析技术

    写在前面的话 理解恶意软件的真实代码对恶意软件分析人员来说是非常有优势的,因为这样才能够真正了解恶意软件所要做的事情.但不幸的是,我们并不总是能够得到“真实”的代码,有时恶意软件分析人员可能需要类似反 ...