对象数组的每个组合

时间:2012-12-17 14:51:20

标签: java recursion combinations

基本上,我有一个包含25个不同人的数组,我需要选择其中5个人,并且每个组合都可以,而不使用同一个人的副本。

我能想到的唯一合乎逻辑的方法是使用5个for循环并检查是否已经使用过人,尽管看起来似乎有一个更好的方法涉及递归。

如果有人可以提供帮助,我将非常感激。

以下是我班级的一个例子;

public class Calculator {

    final Person[] people = new Person[25]; //Pretend we have filled in this info already

    public List<Group> generateList()
    {
        final List<Group> possible = new ArrayList<>();
        for (int a = 0; a < 25; a++)
        {
            for (int b = 0; b < 25; b++)
            {
                for (int c = 0; c < 25; c++)
                {
                    for (int d = 0; d < 25; d++)
                    {
                        for (int e = 0; e < 25; e++)
                        {
                            final Group next = new Group();
                            next.set = new Person[] {
                                people[a],
                                people[b],
                                people[c],
                                people[d],
                                people[e]
                            };
                            possible.add(next);
                        }
                    }
                }
            }
        }
        return possible;
    }



    class Group {

        Person[] set = new Person[5];

    }

    class Person {

        String name;
        int age;

    }

}

然而,我不确定这样做的最好方法,如果这样就能得到所有组合。我也知道这里没有重复检查,我通过检查来做;

如果(b == a)继续;

我将不胜感激。

2 个答案:

答案 0 :(得分:9)

一种可能性是使用组合库,如:http://code.google.com/p/combinatoricslib/

// Create the initial vector
   ICombinatoricsVector<String> initialVector = Factory.createVector(
      new String[] { "red", "black", "white", "green", "blue" } );

   // Create a simple combination generator to generate 3-combinations of the initial vector
   Generator<String> gen = Factory.createSimpleCombinationGenerator(initialVector, 3);

   // Print all possible combinations
   for (ICombinatoricsVector<String> combination : gen) {
      System.out.println(combination);
   }

示例来自项目页面(参见链接)。将它转移到您的用例应该很容易。

答案 1 :(得分:2)

有很多选择。

(1)

你可以使用

改善你的算法
for a = 0 to 25 
  for b = a+1 to 25  // use ascending-order rule 
    for c = b+1 to 25

等 - 这消除了重复检查,利用了问题的因子性质

(2)

您也可以将这些作为整个N ^ R项目的单个for循环实现(如果您从N中选择R项目),并丢弃不完全升序的排列。如果您事先不知道R,这很好。想象一下,你在基数N

for i = 0 to N^R // count in base N
  for digit = 0 to R 
    value[digit] = (i/N^digit) mod (N^(digit+1)) // extract the required digit
    if digit>0 && value[digit]<value[digit-1], SKIP  

换句话说,你按顺序计算这些R指数。

(3)

最后一个选项,即代码更长但对大R和N更有效,是使用一组索引:

// i is an array size R, with items ranging from 0 to N
i = int[]{ 0, 1, 2, 3, 4 }; // each is an index of the items in N

while !finished
    j=0; // index to start incrementing at
    i[j] ++;

然后,如果您在任何索引上超过N,请增加j,增加i[j],并将所有i[k<j]设置为[0 1 2 ... j-1],然后开始计算再次! 这通过所有组合最有效地循环。