Overview:
I am trying to implement the Johnson Trotter Algorithm in Java so that I can solve a problem on Project Euler. I have looked and looked but as far as I can see I have everything implemented right, which you know is wrong, otherwise I wouldn’t be asking this question 🙂
The basic algorithm goes like this:
Johnson Trotter(n)
//Input: A positive integer n
//Output: A list of all permutations(0..n)
initialize the first permutation with: <0, <1, <2
//(all elements pointing left)
while ( //there exists a mobile element )
//find the largest mobile element K
//swap K with the element it points toward
//reverse the direction of all elements > K
//add the permutation to a list
I have created an Element object that has attributes (value, isMobile, Direction) to use for this algorithm. When I am swapping values, only one swap occurs, then after that the original order is printed over and over.
Code:
public void generatePermutations(int n)
{
ArrayList<String> permutations = new ArrayList<String>();
ArrayList<Element> elements = new ArrayList<Element>();
//Initialize the first permutation,
//all Elements are mobile and point LEFT
for(int i = 0; i < n; i++)
{
elements.add(new Element(i, true, Direction.LEFT));
}
//add initial permutation to the list
permutations.add(combineElementsToString(elements));
while(hasMobileElement(elements))
{
//find the largest mobile element
int maxIndex = getLargestMobileIndex(elements);
Element k = elements.get(maxIndex);
//Swap the largest Element with the Element it points to
if(k.getDirection() == Direction.LEFT)
{
//get the index of the element to the left of k
int leftIndex = (maxIndex - 1) >= 0 ? (maxIndex - 1) : maxIndex;
Collections.swap(elements, maxIndex, leftIndex);
}
else
{
//get the index of the element to the right of k
int rightIndex =
(maxIndex + 1) < elements.size() ? (maxIndex + 1) : maxIndex;
Collections.swap(elements, maxIndex, rightIndex);
}
//reverse the direction of all elements larger than K
for(Element e : elements)
{
//System.out.println(e);
if(e.getValue() > k.getValue())
{
Direction opposite = Direction.opposite(e.getDirection());
e.setDirection(opposite);
}
}
//add the new permutation to the list
permutations.add(combineElementsToString(elements));
if(STOP++ == 10) System.exit(0);
}
}
//converts all the values of the Element
//objects then adds them to a String
public String combineElementsToString(ArrayList<Element> elements)
{
String perm = "";
for(Element e : elements)
{
perm += Integer.toString(e.getValue());
}
return perm;
}
//finds largest Mobile element and returns it's index
public int getLargestMobileIndex(ArrayList<Element> elements)
{
int maxIndex = 0;
for(int i = 0; i < elements.size(); i++)
{
if(elements.get(i).isMobile() && i > maxIndex)
{
maxIndex = i;
}
}
return maxIndex;
}
//determines if there is a remaining mobile element
public boolean hasMobileElement(ArrayList<Element> elements)
{
for(Element e : elements)
{
if(e.isMobile())
return true;
}
return false;
}
Expectations:
I would expect the algorithm to do something like this
Start:
<0 <1 <2
<0 <2 <1
<2 <0 <1
etc
Actual
This is what it actually does
Start:
<0 <1 <2
<0 <2 <1
<0 <2 <1
<0 <2 <1
it doesnt change after the first swap
Any help would be awesome, also if you have comments/pointers about my style those would also be much appreciated, Thanks.
Sorry for long post.
Although you are not posting the complete code here (how you decide if an element is mobile or immobile would be helpful), I suspect your error comes from here:
Since the algorithm said
find the largest mobile element K.Also, I suspect there are problems for your
isMobilemethod, but cannot be sure.Hope this helps!