C 排列i和T[i]

C 排列i和T[i],c,algorithm,permutation,C,Algorithm,Permutation,假设我有一个int T数组, 我正在寻找一种置换I和T[I]的就地算法 我有:[3 2 0 1](a) 我要:[2 3 1 0](b) in(b)T[0]=2,因为in(a)T[2]等于0 我希望找到一个简单的O(n)时间,O(1)空间算法,但我找不到。有什么想法吗 注: 有一个单格数组(a)在(b)之后 数组中的值属于[0,N],不重复 要获得置换的反转,只需遍历置换的循环即可 int i, j, next, prev; for(int i=0; i<N; i++) { if(T[

假设我有一个int T数组, 我正在寻找一种置换I和T[I]的就地算法

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

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

in(b)T[0]=2,因为in(a)T[2]等于0

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

注:

  • 有一个单格数组(a)在(b)之后

  • 数组中的值属于[0,N],不重复


要获得置换的反转,只需遍历置换的循环即可

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;
inti,j,next,prev;
对于(int i=0;i=N)继续;
j=T[i];
prev=i;
while(j对于(int i=0;i,您可以使用字典排序来获得所有可能的排列。请按照下面的链接查看排列算法列表


您似乎在寻找数组的倒数。您的示例数组是{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]。因此,要求逆,只需迭代原始数组并反转索引的映射。这应该可以工作(如果知道长度,可以使用任何数组):

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

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

这是我在没有额外内存的情况下就地解决这个问题的尝试。这是一个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 
//数组打印例程。
void printary(常量字符*str_p,int a[],int n)
{
printf(“%s\n”,stru\p);
对于(int i=0;i
Duplicate:它真的是重复的吗?链接中的问题是关于排列组合的,但这个问题(在(b)T[0]=2,因为在(a)T[2]中等于0)更像是排列反转。是的,在阅读后它不是重复的!@jpalecek:这是相同的事情---(a)告诉你如何排列索引[0 1 2 3],以获得(b) @jpalecek:我的回答是:b[j]=ia[i]=j相当于b[a[i]=i,它相当于a[b[j]=j。它工作得很好,但我不能有大于2^31的值(假设我有32位iteger),对吧?当然你可以“正常地”这样做并分配一个标志数组,用于存储到目前为止已处理的元素。我只是想找到一个就地解决方案。但2^31限制是正确的。不幸的是,不是O(1)空间算法。哦,对了……略过了就地要求。好吧,值得一试;我将更详细地研究另一种算法。但是jpalecek的算法也不是O(1)算法。理论上,如果你有[3,0,2,1,4],这是可行的举个例子,我认为当你有太长的链时,你会排列你以前已经排列过的对。无论如何,谢谢!
// 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