Java中高效的判断数组中某个元素是否存在详解
一、检查数组是否包含某个值的方法
使用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能有一定的帮助,如果有疑问大家可以留言交流。
上一篇: mysql 5.7.12二进制安装
下一篇: CentOS7下安装部署superset