以递归方式计算所有数组元素组合

时间:2017-11-23 23:08:47

标签: java arrays recursion combinations permutation

我有一个程序,给定一个数组,返回其值的所有可能组合(排列?)。我递归地这样做。并且它计算好了,但是,我想要做的是,而不是每次迭代打印结果数组,我想将它附加到我之前声明的数组列表。

public static final int NUMBER_OF_CELLS = 3;
public static final int NUMBER_OF_ATTRIBUTES = 3;
// I want all possible combinations all elements 0, 1 and 2, taken 3 at a time 

private ArrayList<State> states= new ArrayList<State>();

public void createAllPossibleStates() {
        State state = new State(NUMBER_OF_CELLS);
        setValues(0, state);
        System.out.println(states);  // This gives me a wrong ouput and I don't know why
    }

public void setValues(int cell, State state) {
        if(cell == NUMBER_OF_CELLS) {
                // System.out.println(state.toString());  // Instead of this
                states.add(state);  // I want this. Append the array to an array list
            }
        }
        else {
            for(int i = 0; i < NUMBER_OF_ATTRIBUTES; i++) {
                state.values[cell] = i;
                setValues(cell + 1, state);
            }
        }
    }

但最终Array List的结果包含所有可能的状态是错误的。而不是:

[[0, 0, 0],[0, 0, 1],[0, 0, 2],[0, 1, 0],[0, 1, 1],[0, 1, 2],[0, 2, 0],[0, 2, 1],[0, 2, 2],[1, 0, 0],[1, 0, 1],[1, 0, 2],[1, 1, 0],[1, 1, 1],[1, 1, 2],[1, 2, 0],[1, 2, 1],[1, 2, 2],[2, 0, 0],[2, 0, 1],[2, 0, 2],[2, 1, 0],[2, 1, 1],[2, 1, 2],[2, 2, 0],[2, 2, 1],[2, 2, 2]]

我明白了:

[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]]

我不禁想知道为什么会这样。也许递归事实导致追加操作工作错误?

2 个答案:

答案 0 :(得分:1)

<强>您好,

您总是将相同的State对象添加到ArrayList。 每个递归循环都在修改相同的State对象。

您必须在State类中实现clone:

@Override
protected State clone() throws CloneNotSupportedException {
    State state = new State(NUMBER_OF_CELLS);
    System.arraycopy(this.values, 0, state.values, 0, this.values.length);

    return state;
}

states.add(state);替换为states.add(state.clone());

答案 1 :(得分:1)

您只有1个State实例,并且您将其传递给调用堆栈,对其进行修改,然后将其多次添加到列表中(每次递归终止一次)。当然,由于只涉及一个对象,它将具有任何状态(没有双关语意图)是给予它的最后一个状态。

如果不修改太多代码,则需要复制State对象并将副本添加到列表中 - 以便在将其添加到列表时永久捕获状态清单。

有一些标准的方法可以做到这一点,但也许最容易理解和最常用的是复制构造函数

public State(State state) {
    this.values = Arrays.copyOf(state.values, state.values.length);
    // copy over whatever other fields you need
} 

然后在你的代码中:

states.add(new State(state));