Questions in black, solutions in blue.
The permutations of an n-element set are the n! different
listings of it as a sequence. Here is a Java class that stores a
permutation as an array of int
variables with the numbers
{1,...,n} in some order. The second array arrow
is used
in the Johnson-Trotter algorithm below.
public class Permutation
int n; // size of set
int [] a; // values from 1 through n in some order
boolean [] arrow; // true means left, false means right
public Permutation (size)
{// creates new identity permutation of given size
n = size;
a = new int[n];
arrow = new boolean[n];
for (int i=0; i < n; i++)
{a[i] = i+1; arrow[i] = true;}
public void swap (int i, int j)
{// swaps both value and arrow in position i and j
int ti = a[i]; a[i] = a[j]; a[j] = ti;
boolean tb = arrow[i]; arrow[i] = arrow[j]; arrow[j] = tb;}
boolean
method next()
that changes the calling Permutation
into the next one given by the Johnson-Trotter method, updating the arrows.
Levitin's description of the process is ``if there is a mobile integer k,
find the largest one, swap it with the neighbor it points to, and reverse the
arrows of all integers larger than k''. ``Mobile'' means ``pointing to a
smaller integer''. Your method should return true
if the update
happens, or false
if there is no mobile integer.
This method would be used as follows to print all the permutations of size n:
Permutation p = new Permutation(n);
boolean done = false;
while (!done) {
System.out.println(p); // using a "toString" method to be written
done = !p.next();}
public boolean mobile (int i)
{//returns whether item i of calling object points to smaller item
if ((i > 0) && (a[i-1] < a[i])) return true; // "&&" is important
if ((i < n-1) && (a[i+1] < a[i])) return true; // here as well
return false;}
public boolean next()
{//changes calling object to next on in Johnson-Trotter order
//locate mobile item with largest value
int k = 0, kspot = 0; // will be largest mobile and its location
int place = 1;
while (place < n) {
while (!mobile(place)) place++;
if (a[place] > k) {
k = a[place]; kspot = place;
place++;}
if (k == 0) return false; // if so there was no mobile at all
if (arrow[kspot]) swap (kspot, kspot-1);
else swap (kspot, kspot+1);
for (place = 0; place < n; place++)
if (a[place] > k) arrow[place] = !arrow[place];
return true;}
boolean
method lex
that changes the
calling Permutation
to the next one in lexicographical order. Ignore the arrows. Levitin gives
an outline for this: ``If the last item an-1 is
greater than the next
to last item an-2, swap them.
Otherwise find the largest i such that
ai < ai+1. Let aj be the smallest
value with j > i and aj > ai.
Put aj in position i, and fill positions ai+1 through
an-1
with the rest of the elements formerly in positions ai through
an-1,
in increasing order.'' (I found the easiest way to do this was to make a new
array b element by element, without changing a, and then assign b
to a.)
Again, your method should return true
if the change is made and
false
if the current
Permutation is already last in lexicographic order.
public boolean lex()
{// changes calling object to next permutation in lex order
// ignores arrow field of calling object, may mess up "next"
int try; // loop index
if (n == 1) return false;
if (a[n-1] > a[n-2]) {swap(n-1, n-2); return true;}
int i; boolean found = false;
for (try = 0; try < n-1; try++)
if (a[try] < a[try+1]) {
found = true;
i = try;}
if (!found) return false; // calling permutation is reverse order
// now i is last item before descending sequence i+1..n
int j = i, best = n+1;
for (try = i+1; i < n; i++)
if ((a[try] < best) && (a[try] > a[i])) {
best = a[try];
j = try;}
// assemble answer in new array, could avoid this by right swaps
int[] b = new int[n];
for (try = 0; try < i; try++) b[try] = a[try];
b[i] = a[j];
int bspot = i+1;
// now copy a[i] through a[n-1], excepting a[j], into b in order
swap(i,j); // now a[i+1] through a[n-1] are right elements in
// reverse order -- we've altered a but that's ok
for (try = n-1; try > i; try--) {
b[bspot] = a[try];
bspot++;}
a = b;
return true;
Last modified 22 October 2003