2011-07-29 24 views
2

概述:約翰遜特羅特算法

我想實現約翰遜豬蹄算法在Java中,這樣我可以在Project Euler解決問題。我已經找了又找,但據我可以看到我把一切都實現正確的,你知道是錯的,否則我就不會問這個問題:)

的基本算法是這樣的:

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 

我創建了一個Element對象,該對象具有用於此算法的屬性(value, isMobile, Direction)。當我交換值時,只發生一次交換,然後在原來的訂單上反覆打印。

代碼:

 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; 
     } 

期望: 我期望算法做這樣的事

開始:

<0 <1 <2 
<0 <2 <1 
<2 <0 <1 

實際

這就是它實際上

開始:

<0 <1 <2 
<0 <2 <1 
<0 <2 <1 
<0 <2 <1 

它不第一個交換後更改

任何幫助將是真棒,此外,如果您有意見/關於我的風格的指針,也將非常感謝,謝謝。

對不起,對於很長的文章。

回答

3

雖然你是不是在這裏張貼的完整代碼(你如何決定,如果一個元素是移動或固定的將是有益的),我懷疑你的錯誤來自這裏:

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; 
     } 

由於算法說find the largest mobile element K

此外,我懷疑你的isMobile方法有問題,但不能確定。

希望這會有所幫助!

+0

謝謝!這絕對是我沒有看到的問題。現在最大的元素交換到左邊,然後沒有其他事情發生。無論謝謝。 –

+1

@獵人我懷疑你的isMobile有問題。你確定它不是:1)只檢查左邊的移動元素2)如果最大元素位於列表的最左邊,則將最大元素視爲移動元素? –

+0

你又對了。無論位置如何,我仍然在考慮2最大。謝謝 –

0

你甚至可以從here

0

這裏下載這個完整的Java源代碼,以連的加速是JOHSON豬蹄算法

公共類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); 
} 

Java代碼}

3

我看着建議的鏈接與Even的加速並認爲它是不需要的沒有效率,使用比較。我的理解是Even的加速意味着你不需要比較。

這是我的代碼;這種迭代形式(與遞歸解決方案不同)允許您調用getNext迭代器來生成並返回下一個排列。

// 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; 
    }