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 bu
I looked at the suggested link with Even's speedup and think it is unnecessarily inefficient, using compares. My understanding is that Even's speedup means you don't need compares.
Here's my code; this iterative form (unlike the recursive solution) allows you to call a getNext iterator to generate and return the next permutation.
// Johnson-Trotter algorithm (http://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm)
public class Permuter {
private int[] perms;
private int[] indexPerms;
private int[] directions;
private int[] iSwap;
private int N; //permute 0..N-1
private int movingPerm=N;
static int FORWARD=+1;
static int BACKWARD=-1;
Permuter(int N) {
this.N = N;
perms = new int[N]; // permutations
indexPerms = new int[N]; // index to where each permutation value 0..N-1 is
directions = new int[N]; // direction = forward(+1) or backward (-1)
iSwap = new int[N]; //number of swaps we make for each integer at each level
for (int i = 0; i < N; i++) {
directions[i] = BACKWARD;
perms[i] = i;
indexPerms[i] = i;
iSwap[i] = i;
}
movingPerm = N;
}
int[] getNext() {
//each call returns the next permutation
do{
if (movingPerm == N) {
movingPerm--;
return perms;
} else if (iSwap[movingPerm] > 0) {
//swap
int swapPerm = perms[indexPerms[movingPerm] + directions[movingPerm]];
perms[indexPerms[movingPerm]] = swapPerm;
perms[indexPerms[movingPerm] + directions[movingPerm]] = movingPerm;
indexPerms[swapPerm] = indexPerms[movingPerm];
indexPerms[movingPerm] = indexPerms[movingPerm] + directions[movingPerm];
iSwap[movingPerm]--;
movingPerm=N;
} else {
iSwap[movingPerm] = movingPerm;
directions[movingPerm] = -directions[movingPerm];
movingPerm--;
}
} while (movingPerm > 0);
return null;
}
Here is the java code for Johson Trotter Algorithm
public class PermutationGenerator {
public void generatePermute(int N)
{
ModifiedInteger[] permute=new ModifiedInteger[N];
int noOfPermutation=0;
for(int i=0;i<N;i++){
permute[i]=new ModifiedInteger(i,i+1,true);
}
System.out.print(++noOfPermutation+" ");
for(ModifiedInteger element:permute){
System.out.print(element.value+",");
}
System.out.println();
ModifiedInteger mobile;
while((mobile=largestMobile(permute))!=null)
{
//System.out.println("Largest Mobile is val- "+mobile.value+" index is "+mobile.index);
swap(mobile,permute);
//System.out.println("After Swap Largest Mobile is val- "+mobile.value+" index is "+mobile.index);
reverse(permute,mobile);
System.out.print(++noOfPermutation+" ");
for(ModifiedInteger element:permute){
System.out.print(element.value+",");
}
System.out.println();
}
}
public void reverse(ModifiedInteger[] sequence,ModifiedInteger largestMobile){
for(ModifiedInteger element:sequence){
if(element.value>largestMobile.value){
element.direction=!element.direction;
}
}
}
public void swap(ModifiedInteger largestMobileInteger,ModifiedInteger[] sequence)
{
ModifiedInteger temp=largestMobileInteger;
if(largestMobileInteger.direction){
sequence[largestMobileInteger.index]=sequence[largestMobileInteger.index-1];
sequence[largestMobileInteger.index-1]=temp;
sequence[largestMobileInteger.index].index+=1;
largestMobileInteger.index-=1;
}
else{
sequence[largestMobileInteger.index]=sequence[largestMobileInteger.index+1];
sequence[largestMobileInteger.index+1]=temp;
sequence[largestMobileInteger.index].index-=1;
largestMobileInteger.index+=1;
}
}
public ModifiedInteger largestMobile(ModifiedInteger[] sequence){
ModifiedInteger largestMobile=null;
int count=0;
for(ModifiedInteger element:sequence){
if(element.direction&&count!=0&&element.value>sequence[count-1].value)
{
if(largestMobile==null){
largestMobile=element;
}
else if(largestMobile.value<element.value){
largestMobile=element;
}
}
else if(!element.direction&&count<sequence.length-1&&element.value>sequence[count+1].value)
{
if(largestMobile==null){
largestMobile=element;
}
else if(largestMobile.value<element.value){
largestMobile=element;
}
}
count++;
}
return largestMobile;
}
//boolean direction-left-true;right-false
public class ModifiedInteger
{
int value;
int index;
private boolean direction;
ModifiedInteger(int index,int value,boolean direction){
this.index=index;
this.value=value;
this.direction=direction;
}
public boolean getDirection() {
return direction;
}
public void setDirection(boolean direction) {
this.direction = direction;
}
}
public static void main(String args[]){
PermutationGenerator obj=new PermutationGenerator();
obj.generatePermute(5);
}
}
You can even download the complete java source code for this, with Even's speedup from here
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:
public int getLargestMobileIndex(ArrayList<Element> elements)
{
int maxIndex = 0;
for(int i = 0; i < elements.size(); i++)
{
if(elements.get(i).isMobile() && i > maxIndex) //<---------- It seems that
// you should compare the i-th element to the maxIndex-th element, not i and
// maxIndex
{
maxIndex = i;
}
}
return maxIndex;
}
Since the algorithm said find the largest mobile element K
.
Also, I suspect there are problems for your isMobile
method, but cannot be sure.
Hope this helps!