我一直在用一堆不同的方法来搜索集合、集合集合等。做了很多愚蠢的小测试来验证我的理解。这是让我感到困惑的一个(源代码在下面)。
简而言之,我正在生成 N 个随机整数并将它们添加到列表中。该列表未排序。然后我Collections.contains()
用来在列表中查找一个值。我有意寻找一个我知道不会存在的值,因为我想确保探测到整个列表空间。我计时这个搜索。
然后我手动进行另一个线性搜索,遍历列表的每个元素并检查它是否与我的目标匹配。我也计时这个搜索。
平均而言,第二次搜索的时间比第一次长 33%。按照我的逻辑,第一次搜索也必须是线性的,因为列表是未排序的。我能想到的唯一可能性(我立即放弃)是 Java 正在制作我的列表的排序副本只是为了搜索,但是(1)我没有授权使用内存空间和(2)我认为使用如此大的 N 会节省更多的时间。
因此,如果两个搜索都是线性的,那么它们都应该花费相同的时间。Collections 类以某种方式优化了此搜索,但我不知道如何。所以......我错过了什么?
import java.util.*;
public class ListSearch {
public static void main(String[] args) {
int N = 10000000; // number of ints to add to the list
int high = 100; // upper limit for random int generation
List<Integer> ints;
int target = -1; // target will not be found, forces search of entire list space
long start;
long end;
ints = new ArrayList<Integer>();
start = System.currentTimeMillis();
System.out.print("Generating new list... ");
for (int i = 0; i < N; i++) {
ints.add(((int) (Math.random() * high)) + 1);
}
end = System.currentTimeMillis();
System.out.println("took " + (end-start) + "ms.");
start = System.currentTimeMillis();
System.out.print("Searching list for target (method 1)... ");
if (ints.contains(target)) {
// nothing
}
end = System.currentTimeMillis();
System.out.println(" Took " + (end-start) + "ms.");
System.out.println();
ints = new ArrayList<Integer>();
start = System.currentTimeMillis();
System.out.print("Generating new list... ");
for (int i = 0; i < N; i++) {
ints.add(((int) (Math.random() * high)) + 1);
}
end = System.currentTimeMillis();
System.out.println("took " + (end-start) + "ms.");
start = System.currentTimeMillis();
System.out.print("Searching list for target (method 2)... ");
for (Integer i : ints) {
// nothing
}
end = System.currentTimeMillis();
System.out.println(" Took " + (end-start) + "ms.");
}
}
编辑:以下是此代码的新版本。有趣的是,现在我的手动线性循环的执行速度比该contains
方法快 16%(注意:两者都旨在有意搜索整个列表空间,所以我知道它们的迭代次数相等)。我无法解释这 16% 的收益……更多的困惑。
import java.util.*;
public class ListSearch {
public static void main(String[] args) {
int N = 10000000; // number of ints to add to the list
int high = 100; // upper limit for random int generation
List<Integer> ints;
int target = -1; // target will not be found, forces search of entire list space
long start;
long end;
ints = new ArrayList<Integer>();
start = System.currentTimeMillis();
System.out.print("Generating new list... ");
for (int i = 0; i < N; i++) {
ints.add(((int) (Math.random() * high)) + 1);
}
end = System.currentTimeMillis();
System.out.println("took " + (end-start) + "ms.");
start = System.currentTimeMillis();
System.out.print("Searching list for target (method 1)... ");
if (ints.contains(target)) {
System.out.println("hit");
}
end = System.currentTimeMillis();
System.out.println(" Took " + (end-start) + "ms.");
System.out.println();
ints = new ArrayList<Integer>();
start = System.currentTimeMillis();
System.out.print("Generating new list... ");
for (int i = 0; i < N; i++) {
ints.add(((int) (Math.random() * high)) + 1);
}
end = System.currentTimeMillis();
System.out.println("took " + (end-start) + "ms.");
start = System.currentTimeMillis();
System.out.print("Searching list for target (method 2)... ");
for (int i = 0; i < N; i++) {
if (ints.get(i) == target) {
System.out.println("hit");
}
}
end = System.currentTimeMillis();
System.out.println(" Took " + (end-start) + "ms.");
}
}