java - 并行计算集合的所有排列

标签 java recursion parallel-processing combinations java-stream


我需要计算集合的所有排列,并且我有一个代码,但问题是它是线性的并且需要大量时间。

public static <E> Set<Set<E>> getAllCombinations(Collection<E> inputSet) {
    List<E> input = new ArrayList<>(inputSet);
    Set<Set<E>> ret = new HashSet<>();
    int len = inputSet.size();
    // run over all numbers between 1 and 2^length (one number per subset). each bit represents an object
    // include the object in the set if the corresponding bit is 1
    for (int i = (1 << len) - 1; i > 0; i--) {
        Set<E> comb = new HashSet<>();
        for (int j = 0; j < len; j++) {
            if ((i & 1 << j) != 0) {
                comb.add(input.get(j));
            }
        }
        ret.add(comb);
    }
    return ret;
}

我正在尝试使计算并行运行。

我虽然可以选择使用递归编写逻辑,然后并行执行递归调用,但我不太确定如何做到这一点。

非常感谢任何帮助。

最佳答案

没有必要使用递归,事实上,这可能会适得其反。由于每个组合的创建可以独立于其他组合执行,因此可以使用并行流来完成。请注意,您甚至不需要手动执行位操作:

public static <E> Set<Set<E>> getAllCombinations(Collection<E> inputSet) {
    // use inputSet.stream().distinct().collect(Collectors.toList());
    // to get only distinct combinations
    //  (in case source contains duplicates, i.e. is not a Set)
    List<E> input = new ArrayList<>(inputSet);
    final int size = input.size();
    // sort out input that is too large. In fact, even lower numbers might
    // be way too large. But using <63 bits allows to use long values
    if(size>=63) throw new OutOfMemoryError("not enough memory for "
        +BigInteger.ONE.shiftLeft(input.size()).subtract(BigInteger.ONE)+" permutations");

    // the actual operation is quite compact when using the Stream API
    return LongStream.range(1, 1L<<size) /* .parallel() */
        .mapToObj(l -> BitSet.valueOf(new long[] {l}).stream()
            .mapToObj(input::get).collect(Collectors.toSet()))
        .collect(Collectors.toSet());
}

内部流操作(即迭代位)太小,无法从并行操作中受益,特别是因为它必须将结果合并到单个 Set 中。 。但如果要生成的组合数量足够大,并行运行外部流将已经利用所有 CPU 核心。

另一种选择是不使用并行流,而是返回 Stream<Set<E>>本身而不是收集到 Set<Set<E>> ,以允许调用者直接链接消费操作。

顺便说一下,对整个 Set 进行哈希处理(或其中很多)可能非常昂贵,因此最终合并步骤的成本可能会主导性能。返回List<Set<E>>相反可以显着提高性能。这同样适用于返回 Stream<Set<E>> 的替代方案。根本不需要收集组合,因为这也可以在不散列 Set 的情况下工作。 s。

关于java - 并行计算集合的所有排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41041088/

相关文章:

java - 如何在 Vaadin 中使用递归获取子树项?

c++ - 求和到几何序列的无穷大

c - PI到底是如何启动这么多进程的

java - 将 JFrame 从起始方法获取到另一个方法

java - Hadoop实际上是如何接受MR作业和输入数据的?

java - 汉诺塔 - 简单算法

java - 我应该尽可能使用并行流吗?

JavaScript 并行性

java - JOGL:使用 Component.printAll() 在 JFrame 中截取 GLCanvas 的屏幕截图不起作用

java.sql.PreparedStatement.setString 函数使 Varchars 与 double 混淆