如何让这个算法懒惰? (Java)

How to make this algorithm lazy? (Java)

让我们考虑一个函数 P(n),它以自然数作为输入,returns 这样的输出:

P(1) = [[0], [1]]
P(2) = [[0, 0], [1, 0], [0, 1], [1, 1]]
P(3) = [[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]
P(4) = [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 0], [1, 0, 1, 0], [0, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1], [1, 1, 0, 1], [0, 0, 1, 1], [1, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1]]

我不知道这是怎么正式调用的(组合?),但我认为这个例子足以理解我的想法。

我已经使用 Java 进行实施:

static byte[][] permutate(int n) {
    byte[][] ps = new byte[1 << n][n];
    go(ps, 0, ps.length / 2, ps.length, n - 1);
    return ps;
}

static void go(byte[][] as, int l, int m, int h, int depth) {
    if (depth < 0)
        return;

    for (int i = l, j = m; i < m && j < h; ++i, ++j) {
        as[i][depth] = 0;
        as[j][depth] = 1;
    }

    go(as, l, (l + m) / 2, m, depth - 1);
    go(as, m, (m + h) / 2, h, depth - 1);
}

此实现 return 的正确结果,但其内存使用量呈 指数增长 ,特别是在 O(2^n)!


这就是我想要的:这个功能,但是很懒!只在需要时生成这些元组(它们实际上是数组,但这不是重点)并丢弃已经使用的元组。所以,我的问题:

这个函数可以return一个迭代器而不是一个数组吗?如果是,怎么做?

您可以使用不使用递归的不同方法:

public static void main(String[] args) throws Exception {
    Iterator<byte[]> iterator = new PermutationIterator(4);
    while (iterator.hasNext()) {
        System.out.println(Arrays.toString(iterator.next()));
    }
}

private static final class PermutationIterator implements Iterator<byte[]> {
    private final int max;
    private final int n;
    private int current;

    public PermutationIterator(int n) {
        this.n = n;
        this.max = (int) Math.pow(2, n);
    }

    @Override
    public boolean hasNext() {
        return current < max;
    }

    @Override
    public byte[] next() {
        byte[] bytes = new byte[n];
        for (int i = 0; i < n; i++) {
            bytes[i] = (byte) ((current >>> i) & 1);
        }
        current++;
        return bytes;
    }

但是,请注意,这只会为 n <= 31 生成正确的结果。如果你想支持更大的 n,你应该使用 long 甚至 BigInteger

输出:

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