Tips implementing permutation algorithm in Java

10,681

Solution 1

As per Howard's advice, I decided I didn't want to use anything but the primitive array type. The algorithm I initially picked was a pain to implement in Java, so thanks to stalker's advice, I went with the lexicographic-ordered algorithm described at Wikipedia. Here's what I ended up with:

public static int[][] generatePermutations(int N) {
    int[][] a = new int[factorial(N)][N];
    for (int i = 0; i < N; i++) a[0][i] = i;
    for (int i = 1; i < a.length; i++) {
        a[i] = Arrays.copyOf(a[i-1], N);
        int k, l;
        for (k = N - 2; a[i][k] >= a[i][k+1]; k--);
        for (l = N - 1; a[i][k] >= a[i][l]; l--);
        swap(a[i], k, l);
        for (int j = 1; k+j < N-j; j++) swap(a[i], k+j, N-j);
    }
    return a;
}
private static void swap(int[] is, int k, int l) {
    int tmp_k = is[k];
    int tmp_l = is[l];
    is[k] = tmp_l;
    is[l] = tmp_k;
}

Solution 2

As you know the number of permutations beforehand (it's N!) and also you want/have to return an int[][] I would go for an array directly. You can declare it right at the beginning with correct dimensions and return it at the end. Thus you don't have to worry about converting it afterwards at all.

Solution 3

The java arrays are not mutable (in the sense, you cannot change their length). For direct translation of this recursive algorithm you probably want to use List interface (and probably LinkedList implementation as you want put numbers in the middle). That is List<List<Integer>>.

Beware the factorial grows rapidly: for N = 13, there is 13! permutations that is 6 227 020 800. But I guess you need to run it for only small values.

The algorithm above is quite complex, my solution would be:

  • create List<int[]> to hold all permutations
  • create one array of size N and fill it with identity ({1,2,3,...,N})
  • program function that in place creates next permutation in lexicographical ordering
  • repeat this until you get the identity again:
    • put a copy of the array at the end of the list
    • call the method to get next permutation.

If your program just needs to output all permutations, I would avoid to store them and just print them right away.

The algorithm to compute next permutation can be found on internet. Here for example

Share:
10,681

Related videos on Youtube

Trevor Dixon
Author by

Trevor Dixon

I do Typescript and Polymer at YouTube and Go after work.

Updated on May 29, 2022

Comments

  • Trevor Dixon
    Trevor Dixon about 2 years

    As part of a school project, I need to write a function that will take an integer N and return a two-dimensional array of every permutation of the array {0, 1, ..., N-1}. The declaration would look like public static int[][] permutations(int N).

    The algorithm described at http://www.usna.edu/Users/math/wdj/book/node156.html is how I've decided to implement this.

    I wrestled for quite a while with arrays and arrays of ArrayLists and ArrayLists of ArrayLists, but so far I've been frustrated, especially trying to convert a 2d ArrayList to a 2d array.

    So I wrote it in javascript. This works:

    function allPermutations(N) {
        // base case
        if (N == 2) return [[0,1], [1,0]];
        else {
            // start with all permutations of previous degree
            var permutations = allPermutations(N-1);
    
            // copy each permutation N times
            for (var i = permutations.length*N-1; i >= 0; i--) {
                if (i % N == 0) continue;
                permutations.splice(Math.floor(i/N), 0, permutations[Math.floor(i/N)].slice(0));
            }
    
            // "weave" next number in
            for (var i = 0, j = N-1, d = -1; i < permutations.length; i++) {
                // insert number N-1 at index j
                permutations[i].splice(j, 0, N-1);
    
                // index j is  N-1, N-2, N-3, ... , 1, 0; then 0, 1, 2, ... N-1; then N-1, N-2, etc.
                j += d;
                // at beginning or end of the row, switch weave direction
                if (j < 0 || j >= N) {
                    d *= -1;
                    j += d;
                }
            }
            return permutations;
        }
    }
    

    So what's the best strategy to port that to Java? Can I do it with just primitive arrays? Do I need an array of ArrayLists? Or an ArrayList of ArrayLists? Or is there some other data type that's better? Whatever I use, I need to be able to convert it back into a an array of primitive arrays.

    Maybe's there a better algorithm that would simplify this for me...

    Thank you in advance for your advice!

  • Trevor Dixon
    Trevor Dixon about 13 years
    Good advice; that's almost what I ended up doing. I found that lexicographical algorithm to be much easier to implement in Java. Thank you very much!