在Java中怎样高效的推断数组中是否包括某个元素
来自 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中怎样高效的推断数组中是否包括某个元素的更多相关文章
- 在Java中如何高效的判断数组中是否包含某个元素
原文出处: hollischuang(@Hollis_Chuang) 如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Ove ...
- java中如何高效的判断数组中是否包含某个元素---
package zaLearnpackage; import org.apache.commons.lang3.ArrayUtils; import java.util.Arrays; import ...
- 【Java】 剑指offer(51)数组中的逆序对
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成 ...
- 【c语言】二维数组中的查找,杨氏矩阵在一个二维数组中,每行都依照从左到右的递增的顺序排序,输入这种一个数组和一个数,推断数组中是否包括这个数
// 二维数组中的查找,杨氏矩阵在一个二维数组中.每行都依照从左到右的递增的顺序排序. // 每列都依照从上到下递增的顺序排序.请完毕一个函数,输入这种一个数组和一个数.推断数组中是否包括这个数 #i ...
- JS中split使用方法和数组中元素的删除
JS中split使用方法和数组中元素的删除 JS中split使用方法 <script language="javascript"> function spli(){ d ...
- Java 高效检查一个数组中是否包含某个值
如何检查一个数组(未排序)中是否包含某个特定的值?在Java中,这是一个非常有用并又很常用的操作.同时,在StackOverflow中,有时一个得票非常高的问题.在得票比较高的几个回答中,时间复杂度差 ...
- 【Java】 剑指offer(39) 数组中出现次数超过一半的数字
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如 ...
- 【Java】 剑指offer(53-3) 数组中数值和下标相等的元素
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 假设一个单调递增的数组里的每个元素都是整数并且是唯一的.请编程 ...
- 【Java】 剑指offer(56-1) 数组中只出现一次的两个数字
本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程 ...
随机推荐
- 第二部分:Spring中配置mongodb
一.需要引用的jar包 1.spring-data-mongodb-1.9.4.RELEASE.jar 2.spring-data-commons-1.12.11.RELEASE.jar 3.mong ...
- EXCEL匹配结果match并跳转链接hyperlink
1,有时候想要搜索另一个表格中含有相同内容的项,然后跳转到搜索结果单元. 需要用到两个函数,MATCH和HYPERLINK 2,A表格如下 B表格如下 3,在B2单元格中输入函数 =HYPERLINK ...
- 第四步:查看StandardAnalyzer的分词效果并添加停用词
LUCENE的创建索引有好多种分词方式,这里我们用的StandardAnalyzer分词 package cn.lucene; import java.io.IOException; import o ...
- 推荐一个国内的免费公共静态cdn
https://cdn.baomitu.com/ 更新速度比bootcdn要快,收录的库也很齐全.
- NMAP输出结果中CPE的含义
NMAP输出结果中CPE的含义 CPE全称是Common Platform Enumeration,意思是通用平台枚举项.它是NMAP对识别出来的软件.操作系统和硬件的一种命名方式.它的格式如下: ...
- Codeforces Round #325 (Div. 2) Laurenty and Shop 模拟
原题链接:http://codeforces.com/contest/586/problem/B 题意: 大概就是给你一个两行的路,让你寻找一个来回的最短路,并且不能走重复的路. 题解: 就枚举上下选 ...
- 洛谷 P3804 后缀自动机
题目描述 给定一个只包含小写字母的字符串SS , 请你求出 SS 的所有出现次数不为 11 的子串的出现次数乘上该子串长度的最大值. 输入输出格式 输入格式: 一行一个仅包含小写字母的字符串SS 输出 ...
- 【codevs1907】【方格取数3】二分图最大带权独立集
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=59001242 向大(hei)佬(e)势力学(di ...
- [洛谷3796]【模板】AC自动机(加强版)
题目大意: 给定$n(n\leq150)$个模式串$p_i(|p_i|\le70)$和一个$t(|t|\le10^6)$,求$t$中被匹配次数最多的$p_i$. 思路: AC自动机.匹配时记录一下匹配 ...
- linux内存查看方法
cat /proc/meminfo 查看RAM使用情况,最简单的方法是通过/proc/meminfo.这个动态更新的虚拟文件实际上是许多其他内存相关工具(如:free / ps / top)等的组合显 ...