PermutationEncoding.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.util.NoSuchElementException; | |
import java.util.PrimitiveIterator; | |
import java.util.function.IntConsumer; | |
/** | |
* @author Devin Smith | |
*/ | |
public class PermutationEncoding { | |
/** | |
* Returns a primitive int iterator with each of the values 0, 1, ..., n - 1 exactly once. | |
* | |
* Note: is easily generalized w/ long or BigInteger | |
*/ | |
private static PrimitiveIterator.OfInt permutation(final int permutationIndex, final int n) { | |
if (!(n >= 0 && n <= 12)) { | |
// fact(13) too large for int | |
throw new IllegalStateException("Only works with 0 <= n <= 12"); | |
} | |
return new PrimitiveIterator.OfInt() { | |
int[] indices = new int[n]; | |
int index = 0; | |
int value = permutationIndex; | |
{ | |
Arrays.setAll(indices, i -> i); | |
} | |
@Override | |
public boolean hasNext() { | |
return index < n; | |
} | |
@Override | |
public int nextInt() { | |
if (!hasNext()) { | |
throw new NoSuchElementException(); | |
} | |
// This is essentially a lazy shuffle algorithm, where our permutation order is | |
// given by the permutationIndex | |
// our first chosen will be between [0, N - 1] | |
// our next chosen will be between [0, N - 2] | |
// etc | |
final int chosen = value % (n - index); | |
value /= (n - index); | |
// swap indices | |
final int tmp = indices[chosen + index]; | |
indices[chosen + index] = indices[index]; | |
indices[index] = tmp; | |
// I *think* there are more efficient ways to go from a permutationIndex to returned | |
// index. In particular, the array seems inefficient. Of course, if we are keeping | |
// the full state around (permutationIndex), that takes up O(N log N) space, same as | |
// the array. | |
++index; | |
return tmp; | |
} | |
}; | |
} | |
private static int fact(int n) { | |
return n == 0 ? 1 : n * fact(n - 1); | |
} | |
public static void main(String[] args) { | |
final int N = 4; | |
final int L = fact(N); | |
for (int i = 0; i < L; ++i) { | |
permutation(i, N) | |
.forEachRemaining((IntConsumer)System.out::print); | |
System.out.println(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment