Java 为什么代码使用较小的列表实例化哈希集?

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<>();

我正在查看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<>();

        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,我明白了。非常感谢。