2016-12-29 37 views
1

我一直在尝试执行在此线程中讨论的内容Algorithm to apply permutation in constant memory space。但是我无法正确理解问题解决方案,或者我的代码有一些我无法检测和修复的错误。蚂蚁的帮助表示赞赏。无法实现阵列就地排列的工作

public class ArrayPermute{ 

    public static void main(String[] args){ 
      char[] arr = {'a','b','c','d'}; 
      int[] p = {2,0,1,3}; 

      for(int i=0; i<arr.length; i++){ 
        int tmp = i; 
        while(p[tmp] >= 0){ 
          char t = arr[p[tmp]];//d 
          arr[p[tmp]] = arr[tmp]; 
          arr[tmp]=t; 
          int _tmp = p[tmp]; 
          p[tmp] = -1; 
          tmp = _tmp; 
          print(arr); 
          print(p); 
        } 
      } 

      for(char i: arr){ 
        System.out.print(i + " "); 
      } 

    } 

    public static void print(char[] arr){ 
      for(char c: arr){ 
        System.out.print(c + " "); 
      } 
      System.out.println(); 
    } 

    public static void print(int[] arr){ 
      for(int c: arr){ 
        System.out.print(c + " "); 
      } 
      System.out.println(); 
    } 

}

+1

您的问题究竟是什么?你得到一个不正确的输出?如果是的话,你会得到什么,你期望什么? – kraskevich

+0

是的,输出是错误的。 – wayfare

回答

1

不要使用很数组元素,以保持位移值(即初始数组的元素之间的互换),你这是怎么搞砸你的代码。相反,使用一些O(1)临时变量来保持“置换”值和源自该值的位置。

评论下面的代码,用2测试用例(请注意使用的Arrays.toString,而不是您的自定义print(char[]/int[])方法)

import java.util.Arrays; 

public class InPlacePermutation { 

    static public void inPlacePermute(char arr[], int p[]) { 
    for(int i=0; i<p.length; i++) { 
     if(p[i]<0) continue; // already visited 

     char toMove=arr[i]; // value-at-hand 
     int currIx=i;  // index from where the value-at-hand originated 

     while(currIx>=0 && p[currIx]!=i) { // as long as we aren't back where we started 
     int destIx=p[currIx]; 
     if(destIx<0) { 
      // the permutation is bad, we are stepping again 
      // on places we stepped before. This should not happen 
      throw new IllegalArgumentException("bad permutation"); 
     } 
     // take the value "at hand" before it get overwritten 
     char destVal=arr[destIx]; 
     // place current "value at hand" in the destination 
     arr[destIx]=toMove; 

     // update bookkeeping the vals/indexes values 
     p[currIx]=-1; // mark where we've been 

     currIx=destIx; // then take a step further 
     toMove=destVal; // don't forget to carry the new "value at hand" 
     } 
     // now we are back where we started with a "value at hand" 
     arr[i]=toMove; 
     p[currIx]=-1; // mark the source of the moved value as visited 
    } 
    } 

    static public void main(String[] args) { 
    char[] arr = {'a','b','c','d'}; 
    int[] p = {2,0,1,3}; 

    System.out.print("arr:"+Arrays.toString(arr)+" + pmt:"+Arrays.toString(p) + " =>"); 
    inPlacePermute(arr, p); 
    System.out.println(" "+Arrays.toString(arr)); 
    System.out.println(); 

    // two cycles and one in place 
    arr = new char[]{'a','b','c','d', 'e', 'f'}; 
    p = new int[]{2,3,4,1,0,5}; 
    System.out.print("arr:"+Arrays.toString(arr)+" + pmt:"+Arrays.toString(p) + " =>"); 
    inPlacePermute(arr, p); 
    System.out.println(" "+Arrays.toString(arr)); 
    } 

} 

输出:

arr:[a, b, c, d] + pmt:[2, 0, 1, 3] => [b, c, a, d] 

arr:[a, b, c, d, e, f] + pmt:[2, 3, 4, 1, 0, 5] => [e, d, a, b, c, f] 
+0

很好的解释。现在它是有道理的。谢谢! – wayfare

0

你并不需要做一个交换,当你前往周期的开始。也就是说,它应该像:

int tmp = i; 
int start = i; 
while (p[tmp] >= 0 && p[tmp] != start) { 
    // Your code here doesn't change 
} 
if (p[tmp] == start) { 
    p[tmp] = -1; 
} 
+0

提出了建议的变化,但我认为我没有得到期望的输出。 输入:char [] arr = {'a','b','c','d'}; int [] p = {2,0,1,3};并且输出是[c,a,b,d] 如果您能解释为什么需要这种更改,这也会非常有帮助。 – wayfare

+0

@wayfare [c,a,b,d]对我来说看起来是正确的。您不需要最后一次交换,因为没有它就会转换整个循环。 – kraskevich

+0

不应输出为{b,c,a,d}而不是[c,a,b,d]?因为p = {2,0,1,3},所以'a'去第三个位置而不是第二个位置。 (从0开始索引) – wayfare