今天写代码的过程中遇到一个需求,从大数量的字符串(不重复!)中查找指定的字符串,突然想到集合的几种查找方法,分别是contains,indexOf以及Collections的binarySearch方法,就想尝试一下哪个执行效率更高,以下是测试代码:
public static void main( String[] args )
{
//指定的字符串
String str=null;
//list用于存储生成字符串
List<String> list=new ArrayList<String>();
int cnt=new Random().nextInt(500000);
for(int i =0;i<500000;i++){
String uuid=UUID.randomUUID().toString().replace("-", "");
list.add(uuid);
//将随机位置的字符串赋值给指定字符串str
if(i==cnt){
str=uuid;
}
}
//排序
public static void main( String[] args )
{
//指定的字符串
String str=null;
//list用于存储生成字符串
List<String> list=new ArrayList<String>();
int cnt=new Random().nextInt(500000);
for(int i =0;i<500000;i++){
String uuid=UUID.randomUUID().toString().replace("-", "");
list.add(uuid);
//将随机位置的字符串赋值给指定字符串str
if(i==cnt){
str=uuid;
}
}
//排序
Collections.sort(list);
//使用Collections的二分法
long start1=new Date().getTime();
int idx1 = Collections.binarySearch(list, str);
long end1=new Date().getTime();
if(idx1>=0){
System.out.println("Collections 二分法:"+(end1-start1)+" 索引为:"+idx1);
}else{
System.out.println("Collections 二分法:未找到");
}
//使用Arrays的二分法
//将list转换为字符串数组
String[] array = new String[list.size()];
list.toArray(array);
long start2=new Date().getTime();
int idx2 = Arrays.binarySearch(array, str);
long end2=new Date().getTime();
if(idx2>=0){
System.out.println("Arrays 二分法:"+(end2-start2)+" 索引为:"+idx2);
}else{
System.out.println("Arrays 二分法未找到.......");
}
long start1=new Date().getTime();
int idx1 = Collections.binarySearch(list, str);
long end1=new Date().getTime();
if(idx1>=0){
System.out.println("Collections 二分法:"+(end1-start1)+" 索引为:"+idx1);
}else{
System.out.println("Collections 二分法:未找到");
}
//使用Arrays的二分法
//将list转换为字符串数组
String[] array = new String[list.size()];
list.toArray(array);
long start2=new Date().getTime();
int idx2 = Arrays.binarySearch(array, str);
long end2=new Date().getTime();
if(idx2>=0){
System.out.println("Arrays 二分法:"+(end2-start2)+" 索引为:"+idx2);
}else{
System.out.println("Arrays 二分法未找到.......");
}
//使用list的indexOf方法
long start4=new Date().getTime();
int idx4 = list.indexOf(str);
long end4=new Date().getTime();
if(idx4>=0){
System.out.println("list indexOf:"+(end4-start4)+" 索引为:"+idx4);
}else{
System.out.println("list indexOf:未找到");
}
long start4=new Date().getTime();
int idx4 = list.indexOf(str);
long end4=new Date().getTime();
if(idx4>=0){
System.out.println("list indexOf:"+(end4-start4)+" 索引为:"+idx4);
}else{
System.out.println("list indexOf:未找到");
}
//使用list.contains方法
for(int i=0;i<array.length;i++){
list.add(array[i]);
}
long start3=new Date().getTime();
boolean bl=list.contains(str);
long end3=new Date().getTime();
if(bl){
System.out.println("list contains:"+(end3-start3));
}else{
System.out.println("list contains:未找到");
}
}
for(int i=0;i<array.length;i++){
list.add(array[i]);
}
long start3=new Date().getTime();
boolean bl=list.contains(str);
long end3=new Date().getTime();
if(bl){
System.out.println("list contains:"+(end3-start3));
}else{
System.out.println("list contains:未找到");
}
}
以下是执行结果:
第一次:
Collections 二分法:0 索引为:400793
Arrays 二分法:0 索引为:400793
list indexOf:16 索引为:400793
list contains:12
第二次:
Collections 二分法:0 索引为:301095
Arrays 二分法:0 索引为:301095
list indexOf:16 索引为:301095
list contains:8
第三次:
Collections 二分法:0 索引为:156585
Arrays 二分法:0 索引为:156585
list indexOf:12 索引为:156585
list contains:4
第一次:
Collections 二分法:0 索引为:400793
Arrays 二分法:0 索引为:400793
list indexOf:16 索引为:400793
list contains:12
第二次:
Collections 二分法:0 索引为:301095
Arrays 二分法:0 索引为:301095
list indexOf:16 索引为:301095
list contains:8
第三次:
Collections 二分法:0 索引为:156585
Arrays 二分法:0 索引为:156585
list indexOf:12 索引为:156585
list contains:4
由上可知,二分查找法不愧是大数据量查找的首选方法,当然其缺点也是显而易见的,即必须是有序序列,且就对Arrays和Collections的binarysearch方法来说,其返回的并不一定是查找到第一个匹配值的索引。对于contains和indexOf来说,如果只想知道是不是包含匹配值,则应该使用contains,如果还想返回具体位置,应该使用indexOf,虽然它的效率最低,但返回的是匹配值第一次出现的位置。