Java 为什么代码使用较小的列表实例化哈希集?
我正在查看org.apache.commons.collections4.ListUtils类,注意到代码如下:Java 为什么代码使用较小的列表实例化哈希集?,java,apache-commons,Java,Apache Commons,我正在查看org.apache.commons.collections4.ListUtils类,注意到代码如下: public static <e> List<e> intersection(final List<? extends E> list1, final List<? extends E> list2) { final List<e> result = new ArrayList<>();
public static <e> List<e> intersection(final List<? extends E> list1, final List<? extends E> list2) {
final List<e> result = new ArrayList<>();
List<? extends E> smaller = list1;
List<? extends E> larger = list2;
if (list1.size() > list2.size()) {
smaller = list2;
larger = list1;
}
final HashSet<e> hashSet = new HashSet<>(smaller);
for (final E e : larger) {
if (hashSet.contains(e)) {
result.add(e);
hashSet.remove(e);
}
}
return result;
}
public static List intersection(final List假设较小的列表有M个
条目,较大的列表有N个
条目,该集合为您提供了对基本操作(添加、包含)的恒定时间访问
如果我用大O表示法对这个算法进行分类,那么运行时将是O(M+N)
和额外的内存消耗O(M)
如果我们将较小的列表切换为较大的列表,则观察结果如下:
- 额外的内存使用将增加到
O(N)
,因此这是不这样做的一个原因
- 从理论上讲,运行时不会改变,仍然是
O(M+N)
,但实际上创建一组N
条目比在其上迭代更为重要
如果您想验证这些假设,请尝试使用Java中运行微基准的工具
我用M=1000
,N=10000
运行了一个不科学的基准测试
Benchmark (size) Mode Cnt Score Error Units
IntersectBench.larger 10000 avgt 5 190481.075 ± 6488.649 ns/op
IntersectBench.smaller 10000 avgt 5 125997.594 ± 1616.975 ns/op
有趣的值在Score
中,越小越好。IntersectBench。越小的
与上面的算法相同,IntersectBench。越大的
是交换列表的算法,交换列表的优化被删除。正如你所看到的,未优化的版本慢了50%。让我们说sma列表中有M
个条目,较大的列表中有N
个条目,该集合为您提供对基本操作(添加、包含)的固定时间访问
如果我用大O表示法对这个算法进行分类,那么运行时将是O(M+N)
和额外的内存消耗O(M)
如果我们将较小的列表切换为较大的列表,则观察结果如下:
- 额外的内存使用将增加到
O(N)
,因此这是不这样做的一个原因
- 从理论上讲,运行时不会改变,仍然是
O(M+N)
,但实际上创建一组N
条目比在其上迭代更为重要
如果您想验证这些假设,请尝试使用Java中运行微基准的工具
我用M=1000
,N=10000
运行了一个不科学的基准测试
Benchmark (size) Mode Cnt Score Error Units
IntersectBench.larger 10000 avgt 5 190481.075 ± 6488.649 ns/op
IntersectBench.smaller 10000 avgt 5 125997.594 ± 1616.975 ns/op
有趣的值在分数中,越小越好。IntersectBench。越小的与上面的算法相同,IntersectBench。越大的是交换列表的算法,并且交换列表的优化被删除。正如你所看到的,未优化的版本慢了50%。它更快,并且可以使用it’s内存比另一种情况要少。想象一下,如果一个列表有3个项目,另一个有300万。@tzaman,谢谢你的回答。我理解它使用的内存更少,但为什么更快?在你的示例中它会循环300万次吗?它必须循环300万次;要么将条目放入哈希集,要么对照哈希集进行检查。自然地,检查比添加更快。@tzaman,我明白了。非常感谢。它比其他方法更快,占用的内存也更少。想象一下,如果一个列表有3个项目,另一个有300万。@tzaman,谢谢你的回答。我理解它占用的内存更少,但为什么它更快?在你的示例中,它会循环300万次吗?它必须循环3次无论哪种方式都是百万次;要么将条目放入哈希集,要么对照哈希集进行检查。自然,检查比添加快。@tzaman,我明白了。非常感谢。