置换i和T [i]

时间:2009-03-02 09:05:25

标签: c algorithm permutation

假设我有一个int T数组, 我正在寻找一种可以置换i和T [i]

的就地算法

我有:[3 2 0 1](a)

我想:[2 3 1 0](b)

例如。在(b)T [0] = 2中因为,在(a)中T [2]等于0。

我期待找到一个简单的O(n)时间,O(1)空间算法,但我找不到它。有什么想法吗?

注意:

  • 在(b)之后有一个sigle数组(a)。

  • 数组中的值属于[0,N [,没有重复。

4 个答案:

答案 0 :(得分:4)

要获得排列的反转,你只需要走遍变换的周期

int i, j, next, prev;
for(int i=0; i<N; i++) {
  if(T[i]>=N) continue;
  j=T[i];
  prev=i;
  while(j < N) {
    next=T[j];
    T[j]=prev+N;
    prev=j;
    j=next;
  }
}
for(int i=0; i<N; i++)
  T[i]-=N;

我使用大于N的数字来标记这是已经处理的循环的一部分。

答案 1 :(得分:1)

您可以进行词典排序以获得所有可能的排列。请点击以下链接获取排列算法列表

Permutations

答案 2 :(得分:1)

您似乎正在寻找数组的permutation group中的逆。你的示例数组是{0→3,1→2,2→0,3→1},你想要{3→0,2→1,0→2,1→3}。重新排列,即{0→2,1→3,2→1,3→0}或[2 3 1 0]。因此,要找到逆,您只需要遍历原始数组并反转索引的映射。这应该有用(如果知道长度,可以使用任何数组):

int t[] = { 3, 2, 0, 1};
int tinv[4];
for (int i = 0; i < 4; i++)
    tinv[t[i]] = i;

只要t(长度为n)是[0 .. n-1]的置换,就不应该为任何值定义tinv。 jpalecek的解决方案有点复杂,所以我不确定这个解决方案是否足够全面。

答案 3 :(得分:0)

这是我试图在没有额外内存的情况下就地解决这个问题。它是一种O(n)算法。

jpalecek的算法很聪明,但读起来并不直观,至少对我来说不是这样。我已经尝试了它并且它有效但我没有时间去理解为什么和评论会很棒。

只要数组不是太大,Gracenotes的算法就很棒。如果数据很大,则可能必须动态创建数组。

我的算法的基本思想是通过跟随索引和值对链来更新数组。例如,索引0映射到值3.通过使用值3作为索引,您将找到下一对,即数组中的索引3和值1.本质上,我保存下一个索引和值对并更新先前的索引和值对直到我完成链条。

如果你能让它更高效,更优雅或更好,我会感兴趣。

我编译并测试了下面的代码,但没有使用任何其他测试输入。我已经将调试输出留给了那些希望尝试并更好地理解它是如何工作的人。

// Array print routine.
void printArray (const char * str_p,int a[], int n)
{
   printf ("%s\n", str_p);
   for (int i = 0; i < n; i++)
   {
      printf ("%i ", i);
   }
   printf ("\n");
   for (int i = 0; i < n; i++)
   {
      printf ("%i ", a[i]);
   }
   printf ("\n\n");
}

// The main code.
void PermuteTheDamnArray()
{
   printArray ("Initial Array", a,n);

   int i = 0;     // Simply a counter.
   int p_ix = 0;  // Previous Index.
   int p_val = a[0]; // Previous Value.
   int n_ix = a[0];  // Next index.
   int n_val = a[n_ix]; // Next Value.
   for (i = 0; i < n; i++)
   {
      // Replace. 
      printf ("Swapping orig (%i,%i) with (%i,%i)\n", n_ix, n_val,p_val, p_ix);
      a[p_val] = p_ix;

      printArray ("Array after swap", a,n);

      // The next index and value pair becomes the new previous index and value pair.
      p_ix = n_ix;
      p_val = n_val;
      printf ("The previous pair is now: (%i,%i)\n", p_ix, p_val);

      // Get the next index and value pair.
      n_ix = n_val;
      n_val = a[n_val];
      printf ("The next pair is now: (%i,%i)\n", n_ix, n_val);

   }

   printArray ("Final Array", a,n);
}



Output:

Swapping orig (3,1) with (3,0)
Array after swap
0 1 2 3 
3 2 0 0 

The previous pair is now: (3,1)
The next pair is now: (1,2)
Swapping orig (1,2) with (1,3)
Array after swap
0 1 2 3 
3 3 0 0 

The previous pair is now: (1,2)
The next pair is now: (2,0)
Swapping orig (2,0) with (2,1)
Array after swap
0 1 2 3 
3 3 1 0 

The previous pair is now: (2,0)
The next pair is now: (0,3)
Swapping orig (0,3) with (0,2)
Array after swap
0 1 2 3 
2 3 1 0 

The previous pair is now: (0,3)
The next pair is now: (3,0)
Final Array
0 1 2 3 
2 3 1 0