30

I need to calculate permutations iteratively. The method signature looks like:

int[][] permute(int n)

For n = 3 for example, the return value would be:

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

How would you go about doing this iteratively in the most efficient way possible? I can do this recursively, but I'm interested in seeing lots of alternate ways to doing it iteratively.

Bob Aman
  • 32,839
  • 9
  • 71
  • 95
  • 2
    As I mentioned in my answer (after I edited to use the QuickPerm algorithm as uray suggested), the most efficient way would be to iterate over the permutations live. Building up a complete list is likely not to be very useful, as you can just process the current iteration. – Matthew Mar 06 '10 at 02:23
  • Right, which is why the Ruby code I added to uray's answer uses yield and blocks. It passes each permutation to the supplied code block before calculating the next permutation. – Bob Aman Mar 06 '10 at 04:53
  • 1
    See this question and answers: http://stackoverflow.com/questions/352203/generating-permutations-lazily/ – ShreevatsaR Mar 06 '10 at 17:04
  • @Bob, the C# version I posted uses the same approach of yielding results as they become available. Hope it helps someone out. – Drew Noakes Dec 05 '11 at 11:03

10 Answers10

23

see QuickPerm algorithm, it's iterative : http://www.quickperm.org/

Edit:

Rewritten in Ruby for clarity:

def permute_map(n)
  results = []
  a, p = (0...n).to_a, [0] * n
  i, j = 0, 0
  i = 1
  results << yield(a)
  while i < n
    if p[i] < i
      j = i % 2 * p[i] # If i is odd, then j = p[i], else j = 0
      a[j], a[i] = a[i], a[j] # Swap
      results << yield(a)
      p[i] += 1
      i = 1
    else
      p[i] = 0
      i += 1
    end
  end
  return results
end
juanignaciosl
  • 3,435
  • 2
  • 28
  • 28
uray
  • 11,254
  • 13
  • 54
  • 74
  • I snuck in there and attached a Ruby implementation of this algorithm for my own personal reference. Would've put it in the comments, but you can't have syntax highlighting there. – Bob Aman Mar 06 '10 at 01:30
  • 1
    Incidentally, the current version of Ruby has this built-in: `(0...n).to_a.permutation { |a| puts a.inspect }` – Bob Aman Apr 22 '13 at 01:19
  • 4
    what's time complexity of this one? – aidan Mar 10 '14 at 22:34
6

The algorithm for stepping from one permutation to the next is very similar to elementary school addition - when an overflow occurs, "carry the one".

Here's an implementation I wrote in C:

#include <stdio.h>

//Convenience macro.  Its function should be obvious.
#define swap(a,b) do { \
        typeof(a) __tmp = (a); \
        (a) = (b); \
        (b) = __tmp; \
    } while(0)

void perm_start(unsigned int n[], unsigned int count) {
    unsigned int i;
    for (i=0; i<count; i++)
        n[i] = i;
}

//Returns 0 on wraparound
int perm_next(unsigned int n[], unsigned int count) {
    unsigned int tail, i, j;

    if (count <= 1)
        return 0;

    /* Find all terms at the end that are in reverse order.
       Example: 0 3 (5 4 2 1) (i becomes 2) */
    for (i=count-1; i>0 && n[i-1] >= n[i]; i--);
    tail = i;

    if (tail > 0) {
        /* Find the last item from the tail set greater than
            the last item from the head set, and swap them.
            Example: 0 3* (5 4* 2 1)
            Becomes: 0 4* (5 3* 2 1) */
        for (j=count-1; j>tail && n[j] <= n[tail-1]; j--);

        swap(n[tail-1], n[j]);
    }

    /* Reverse the tail set's order */
    for (i=tail, j=count-1; i<j; i++, j--)
        swap(n[i], n[j]);

    /* If the entire list was in reverse order, tail will be zero. */
    return (tail != 0);
}

int main(void)
{
    #define N 3
    unsigned int perm[N];
    
    perm_start(perm, N);
    do {
        int i;
        for (i = 0; i < N; i++)
            printf("%d ", perm[i]);
        printf("\n");
    } while (perm_next(perm, N));
    
    return 0;
}
phuclv
  • 37,963
  • 15
  • 156
  • 475
Joey Adams
  • 41,996
  • 18
  • 86
  • 115
5

Is using 1.9's Array#permutation an option?

>> a = [0,1,2].permutation(3).to_a
=> [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
  • No, the algorithm itself is what I'm looking for. I marked this as language-agnostic precisely for that reason. – Bob Aman Mar 08 '10 at 16:49
4

Below is my generics version of the next permutation algorithm in C# closely resembling the STL's next_permutation function (but it doesn't reverse the collection if it is the max possible permutation already, like the C++ version does)

In theory it should work with any IList<> of IComparables.

static bool NextPermutation<T>(IList<T> a) where T: IComparable
{
    if (a.Count < 2) return false;
    var k = a.Count-2;

    while (k >= 0 && a[k].CompareTo( a[k+1]) >=0) k--;
    if(k<0)return false;

    var l = a.Count - 1;
    while (l > k && a[l].CompareTo(a[k]) <= 0) l--;

    var tmp = a[k];
    a[k] = a[l];
    a[l] = tmp;

    var i = k + 1;
    var j = a.Count - 1;
    while(i<j)
    {
        tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
        i++;
        j--;
    }

    return true;
}

And the demo/test code:

var src = "1234".ToCharArray();
do
{
    Console.WriteLine(src);
} 
while (NextPermutation(src));
phuclv
  • 37,963
  • 15
  • 156
  • 475
Zar Shardan
  • 5,675
  • 2
  • 39
  • 37
2

I found Joey Adams' version to be the most readable, but I couldn't port it directly to C# because of how C# handles the scoping of for-loop variables. Hence, this is a slightly tweaked version of his code:

/// <summary>
/// Performs an in-place permutation of <paramref name="values"/>, and returns if there 
/// are any more permutations remaining.
/// </summary>
private static bool NextPermutation(int[] values)
{
    if (values.Length == 0)
        throw new ArgumentException("Cannot permutate an empty collection.");

    //Find all terms at the end that are in reverse order.
    //  Example: 0 3 (5 4 2 1) (i becomes 2)
    int tail = values.Length - 1;
    while(tail > 0 && values[tail - 1] >= values[tail])
        tail--;

    if (tail > 0)
    {
        //Find the last item from the tail set greater than the last item from the head 
        //set, and swap them.
        //  Example: 0 3* (5 4* 2 1)
        //  Becomes: 0 4* (5 3* 2 1)
        int index = values.Length - 1;
        while (index > tail && values[index] <= values[tail - 1])
            index--;

        Swap(ref values[tail - 1], ref values[index]);
    }

    //Reverse the tail set's order.
    int limit = (values.Length - tail) / 2;
    for (int index = 0; index < limit; index++)
        Swap(ref values[tail + index], ref values[values.Length - 1 - index]);

    //If the entire list was in reverse order, tail will be zero.
    return (tail != 0);
}

private static void Swap<T>(ref T left, ref T right)
{
    T temp = left;
    left = right;
    right = temp;
}
phuclv
  • 37,963
  • 15
  • 156
  • 475
Leon Bouquiet
  • 4,159
  • 3
  • 25
  • 36
2

I also came across the QuickPerm algorithm referenced in another answer. I wanted to share this answer in addition, because I saw some immediate changes one can make to write it shorter. For example, if the index array "p" is initialized slightly differently, it saves having to return the first permutation before the loop. Also, all those while-loops and if's took up a lot more room.

void permute(char* s, size_t l) {
    int* p = new int[l];
    for (int i = 0; i < l; i++) p[i] = i;
    for (size_t i = 0; i < l; printf("%s\n", s)) {
        std::swap(s[i], s[i % 2 * --p[i]]);
        for (i = 1; p[i] == 0; i++) p[i] = i;
    }
}
user2880576
  • 131
  • 1
  • 8
2

Here's an implementation in C#, as an extension method:

public static IEnumerable<List<T>> Permute<T>(this IList<T> items)
{
    var indexes = Enumerable.Range(0, items.Count).ToArray();

    yield return indexes.Select(idx => items[idx]).ToList();

    var weights = new int[items.Count];
    var idxUpper = 1;
    while (idxUpper < items.Count)
    {
        if (weights[idxUpper] < idxUpper)
        {
            var idxLower = idxUpper % 2 * weights[idxUpper];
            var tmp = indexes[idxLower];
            indexes[idxLower] = indexes[idxUpper];
            indexes[idxUpper] = tmp;
            yield return indexes.Select(idx => items[idx]).ToList();
            weights[idxUpper]++;
            idxUpper = 1;
        }
        else
        {
            weights[idxUpper] = 0;
            idxUpper++;
        }
    }
}

And a unit test:

[TestMethod]
public void Permute()
{
    var ints = new[] { 1, 2, 3 };
    var orderings = ints.Permute().ToList();
    Assert.AreEqual(6, orderings.Count);
    AssertUtil.SequencesAreEqual(new[] { 1, 2, 3 }, orderings[0]);
    AssertUtil.SequencesAreEqual(new[] { 2, 1, 3 }, orderings[1]);
    AssertUtil.SequencesAreEqual(new[] { 3, 1, 2 }, orderings[2]);
    AssertUtil.SequencesAreEqual(new[] { 1, 3, 2 }, orderings[3]);
    AssertUtil.SequencesAreEqual(new[] { 2, 3, 1 }, orderings[4]);
    AssertUtil.SequencesAreEqual(new[] { 3, 2, 1 }, orderings[5]);
}

The method AssertUtil.SequencesAreEqual is a custom test helper which can be recreated easily enough.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
1

How about a recursive algorithm you can call iteratively? If you'd actually need that stuff as a list like that (you should clearly inline that rather than allocate a bunch of pointless memory). You could simply calculate the permutation on the fly, by its index.

Much like the permutation is carry-the-one addition re-reversing the tail (rather than reverting to 0), indexing the specific permutation value is finding the digits of a number in base n then n-1 then n-2... through each iteration.

public static <T> boolean permutation(List<T> values, int index) {
    return permutation(values, values.size() - 1, index);
}
private static <T> boolean permutation(List<T> values, int n, int index) {
    if ((index == 0) || (n == 0))  return (index == 0);
    Collections.swap(values, n, n-(index % n));
    return permutation(values,n-1,index/n);
}

The boolean returns whether your index value was out of bounds. Namely that it ran out of n values but still had remaining index left over.

And it can't get all the permutations for more than 12 objects. 12! < Integer.MAX_VALUE < 13!

-- But, it's so very very pretty. And if you do a lot of things wrong might be useful.

Tatarize
  • 10,238
  • 4
  • 58
  • 64
1

I have implemented the algorithm in Javascript.

var all = ["a", "b", "c"];
console.log(permute(all));

function permute(a){
  var i=1,j, temp = "";
  var p = [];
  var n = a.length;
  var output = [];

  output.push(a.slice());
  for(var b=0; b <= n; b++){
    p[b] = b;
  }

  while (i < n){
    p[i]--;
    if(i%2 == 1){
      j = p[i];
    }
    else{
      j = 0;
    }
    temp = a[j];
    a[j] = a[i];
    a[i] = temp;

    i=1;
    while (p[i] === 0){
      p[i] = i;
      i++;
    }
    output.push(a.slice());
  }
  return output;
}
phuclv
  • 37,963
  • 15
  • 156
  • 475
Imran Rashid
  • 1,328
  • 14
  • 21
0

I've used the algorithms from here. The page contains a lot of useful information.

Edit: Sorry, those were recursive. uray posted the link to the iterative algorithm in his answer.

I've created a PHP example. Unless you really need to return all of the results, I would only create an iterative class like the following:

<?php
class Permutator implements Iterator
{
  private $a, $n, $p, $i, $j, $k;
  private $stop;
    
  public function __construct(array $a)
  {
    $this->a = array_values($a);
    $this->n = count($this->a);
  }
    
  public function current()
  {
    return $this->a;
  }
    
  public function next()
  {
    ++$this->k;
    while ($this->i < $this->n)
    {
      if ($this->p[$this->i] < $this->i)
      {
        $this->j = ($this->i % 2) * $this->p[$this->i];
    
        $tmp = $this->a[$this->j];
        $this->a[$this->j] = $this->a[$this->i];
        $this->a[$this->i] = $tmp;
    
        $this->p[$this->i]++;
        $this->i = 1;
        return;
      }
    
      $this->p[$this->i++] = 0;
    }
    
    $this->stop = true;
  }
    
  public function key()
  {
    return $this->k;
  }
    
  public function valid()
  {
    return !$this->stop;
  }
    
  public function rewind()
  {
    if ($this->n) $this->p = array_fill(0, $this->n, 0);
    $this->stop = $this->n == 0;
    $this->i = 1;
    $this->j = 0;
    $this->k = 0;
  }
    
}
    
foreach (new Permutator(array(1,2,3,4,5)) as $permutation)
{
  var_dump($permutation);
}
?>

Note that it treats every PHP array as an indexed array.

phuclv
  • 37,963
  • 15
  • 156
  • 475
Matthew
  • 47,584
  • 11
  • 86
  • 98