用于生成合成的迭代算法

时间:2017-04-18 07:21:56

标签: java algorithm recursion iteration

我已经实现了一种算法,该算法在Y框中写出X项的所有可能组合(在组合学中,我相信它们被称为组合)。我使用递归函数编写了这个算法,因为它更容易跟踪我们将项目放入的当前框以及剩余的项目数。 该算法给出了以下输出(4个盒子和3个项目):

  

[3,0,0,0],[2,1,0,0],[2,0,1,0],[2,0,0,1],[1,2,0, 0],[1,1,1,0],......,[0,0,1,2],[0,0,0,3]

你可以想象,对于大X和Y,组合的数量会增长很多。由于我不关心订单组合的进展,我想要进一步计算,但我可以&#39 ; t在递归函数上执行此操作(我已尝试通过保存递归状态来执行此操作,但这非常混乱,尽管它有效,但它确实很慢) 。 所以,我想知道是否可以迭代地重新编写相同的函数(使用for循环),以便我可以并行化它。 (需要记住的一点是,优化也很重要,因为我需要为大X和Y运行函数)我的递归函数如下所示:

public void charArrangements (int boxes, int items, String strBuild) {
        if (boxes > 1) {
            for (int i = 0; i <= items; i++) {
                String ss = strBuild + (items - i) + ";";
                charArrangements(boxes - 1, i, ss);
            }
        }
        else {
            String ss = strBuild + items;
            List<Integer> charArrangement = new ArrayList<Integer>();
            charArrangement = Stream.of(ss.split(";")).map(Integer::parseInt).collect(Collectors.toList());

            doCalculations(charArrangement);
        }
} 

6 个答案:

答案 0 :(得分:1)

有线程就像

public void charArrangements (int boxes, int balls, String strBuild) {
    ArrayList<myThread> arr=new ArrayList<>();//fill arraylist
    for(int j=boxes;j>1;j--){
        arr.get(j).start();
    }
}



//put this login in your threads run() method
public void someFunc(int balls, String strBuild)
{
    for (int i = 0; i <= balls; i++) {
        String ss = strBuild + (balls - i) + ";";
        }
}

答案 1 :(得分:0)

我认为你需要这个。让我们试试

public void charArrangements (int boxes, int balls, String strBuild) {
    for(int j=boxes;j>1;j--){
        for (int i = 0; i <= balls; i++) {
            String ss = strBuild + (balls - i) + ";";
            }
    }
}

在此之后你可以做你在else子句中的逻辑。

答案 2 :(得分:0)

您可以在不同的线程和join当前线程中调用递归调用,例如:

public void charArrangements (int boxes, int balls, String strBuild) {
    if (boxes > 1) {
        for (int i = 0; i <= balls; i++) {
            String ss = strBuild + (balls - i) + ";";
            final int count = i;
            try{
                Runnable r = new Runnable() {
                    @Override
                    public void run() {
                        charArrangements(boxes - 1, count, ss);
                    }
                };
                Thread t = new Thread(r);
                t.start();
                t.join();
            }catch(Exception e){
                throw new RuntimeException(e);
            }
        }
    }
    else {
        String ss = strBuild + balls;
        List<Integer> charArrangement = new ArrayList<Integer>();
        charArrangement = Stream.of(ss.split(";")).map(Integer::parseInt).collect(Collectors.toList());
    }
}

P.S。删除了文件写入部分。

答案 3 :(得分:0)

为什么不能并行化递归函数?使用主线程来完成前N个级别(最好的N取决于你的问题空间),然后让并发工作者处理级别N + 1及以后。

答案 4 :(得分:0)

听起来您希望能够更直接地访问累积解决方案的状态;例如,能够保存和恢复它,而不必每次都重建它。实现此目的的一种方法是使用词典生成。

我建议首先创建没有任何零的数字分区,然后添加零并使用已知的简单算法进行下一个词典排列,您可以在线轻松查找。以下是将5个项目分为7个框的示例:

Order partitions in decreasing order by number of parts

[0,0,1,1,1,1,1] -> generate all lexicographic permutations
[0,0,0,1,1,1,2] -> generate all lexicographic permutations
[0,0,0,0,1,2,2] -> ...

以下是我提出的用于相反大小的相反下一个词典分区的算法,也许它可以改进或纠正(我们将其反转,以便我们可以从下一步中排名最低的排列开始):

(0) The first partition is either k (n/k)'s if k divides n,
    or (remainder of n/k) (n/k + 1)'s and (k - remainder of n/k)'s (n/k)'s
    to their left.

(1) Find the leftmost part, l, greater than 1

(2) If l is the rightmost part, we're done.
    Otherwise, decrement l and increment the leftmost part, r,
      right of l that is lower than its right neighbour.
      If r is not found, increment the rightmost part and
        set the rest of the partition according to
        instruction (0), where k and n now would be 
        (k - 1) and (n - rightmost part), respectively.

[0,0,0,0,1,2,2] -> generate all lexicographic permutations
[0,0,0,0,1,1,3] -> ...
etc.

答案 5 :(得分:0)

一个简单但丑陋的迭代算法,用于以反向词典顺序枚举弱k组合,可能如下所示:

static void weakCompositions(int n, int k, Consumer<int[]> callback) {
    assert n >= 0: n;
    assert k >= 0: k;

    if (k == 0)
        return;

    int C[], i, x;
    C = new int[k];
    C[0] = n;

    while (true) {
        callback.accept(C);

        i = k - 2;

        while (i >= 0 && C[i] == 0)
            i--;

        if (i < 0)
            break;

        C[i]--;
        x = C[k - 1] + 1;
        C[k - 1] = 0;
        C[i + 1] = x;
    }
}

其中n是项目数,k是方框数。

不确定它是否适合并行化。

基本思想是在数组的前缀中找到最右边的非零值的位置(即,排除最后的条目);将“转移”1从该位置转移到其右边;并且,进入那个新位置,将所有值吸收到它的右边(如果有任何值,它应该只是数组中的最后一个值,通过构造)。

我认为应该可以跟踪数组前缀的最右边非零值,而不必为生成的每个组合扫描它。这样做也可以更容易地分析算法并查看它是否是恒定的摊销时间。

最后,number of weak k-compositions(n + k - 1)! / n! / (k - 1)!提供。你提到你最后的问题空间是75个盒子中的11个项目,超过21万亿个对象!即使使用并行化,这似乎是......难以理解的。祝你好运!