2012-01-15 30 views
2

考虑阵列a[i],i=0,1,...,g,其中g可以是任何给定数字,并且a[0]=1如何简化这个循环?

for a[1]=a[0]+1 to 1 do 
    for a[2]=a[1]+1 to 3 do 
     for a[3]=a[2]+1 to 5 do 
     ... 
      for a[g]=a[g-1]+1 to 2g-1 do 
       #print a[1],a[2],...a[g]# 

的问题是,每次我们改变g的价值,我们需要修改代码,高于环。这不是一个好的代码。

+5

您有三种语言:C++,MATLAB和Mathematica,您正在尝试使用哪一种语言? – 2012-01-15 04:03:21

+0

欢迎任何语言。 – 2012-01-15 04:14:19

回答

1

递归是解决这个问题的方法之一(尽管我很喜欢看到迭代解决方案)。

!!!警告,未经测试的代码在以下!!!

template<typename A, unsigned int Size> 
void recurse(A (&arr)[Size],int level, int g) 
{ 
    if (level > g) 
    { 
    // I am at the bottom level, do stuff here 
    return; 
    } 

    for (arr[level] = arr[level-1]+1; arr[level] < 2 * level -1; arr[level]++) 
    { 

     recurse(copy,level+1,g); 
    } 
} 

然后用recurse(arr,1,g);

+0

注意:如果g太大,你会得到堆栈溢出(lol ...站点名称) – David 2012-01-15 04:11:38

+0

我已经添加了一个迭代解决方案。 – arx 2012-01-15 05:03:30

+0

这个嵌套函数非常棒。谢谢,Ethan。 – 2012-01-15 05:12:32

0

叫我说你不想在首位嵌套循环。相反,你只是想调用合适的功能,充分利用了当前的嵌套级别,最大嵌套级别(即g),循环的开始,不管是否需要为上下文计算作为参数:

void process(int level, int g, int start, T& context) { 
    if (level != g) { 
     for (int a(start + 1), end(2 * level - 1); a < end; ++a) { 
      process(level + 1, g, a, context); 
     } 
    } 
    else { 
     computation goes here 
    } 
} 
1

想象一下,你用数字数组表示数字。例如,682将是[6,8,2]。

如果你想从0数到999,你可以写:

for (int n[0] = 0; n[0] <= 9; ++n[0]) 
    for (int n[1] = 0; n[1] <= 9; ++n[1]) 
     for (int n[2] = 0; n[2] <= 9; ++n[2]) 
      // Do something with three digit number n here 

但是,当你要数到9999,你需要一个额外的for循环。

取而代之,您可以使用将数字加1的过程:如果最后一位数字溢出,则移至前一位数字,以此类推。当第一个数字溢出时,您的循环完成。这可以处理任意数字的数字。

您需要一个类似的过程来为循环变量“加1”。

递增最后的“数字”,即a[g]。如果溢出(即超过2g-1),则转到下一个最重要的“数字”(a[g-1])并重复。与使用数字做这件事相比,稍微复杂一点是,当数值溢出时,通过数组返回,然后需要前进以将溢出的数字重置为其新的基本值(取决于左边的值)。

以下C#代码实现了这两种方法并将数组输出到控制台。

static void Print(int[] a, int n, ref int count) 
{ 
    ++count; 
    Console.Write("{0} ", count); 
    for (int i = 0; i <= n; ++i) 
    { 
     Console.Write("{0} ", a[i]); 
    } 
    Console.WriteLine(); 
} 

private static void InitialiseRight(int[] a, int startIndex, int g) 
{ 
    for (int i = startIndex; i <= g; ++i) 
     a[i] = a[i - 1] + 1; 
} 

static void Main(string[] args) 
{ 
    const int g = 5; 

    // Old method 
    int count = 0; 
    int[] a = new int[g + 1]; 
    a[0] = 1; 
    for (a[1] = a[0] + 1; a[1] <= 2; ++a[1]) 
     for (a[2] = a[1] + 1; a[2] <= 3; ++a[2]) 
      for (a[3] = a[2] + 1; a[3] <= 5; ++a[3]) 
       for (a[4] = a[3] + 1; a[4] <= 7; ++a[4]) 
        for (a[5] = a[4] + 1; a[5] <= 9; ++a[5]) 
         Print(a, g, ref count); 

    Console.WriteLine(); 
    count = 0; 

    // New method 

    // Initialise array 
    a[0] = 1; 
    InitialiseRight(a, 1, g); 

    int index = g; 
    // Loop until all "digits" have overflowed 
    while (index != 0) 
    { 
     // Do processing here 
     Print(a, g, ref count); 

     // "Add one" to array 
     index = g; 
     bool carry = true; 
     while ((index > 0) && carry) 
     { 
      carry = false; 

      ++a[index]; 
      if (a[index] > 2 * index - 1) 
      { 
       --index; 
       carry = true; 
      } 
     } 
     // Re-initialise digits that overflowed. 
     if (index != g) 
      InitialiseRight(a, index + 1, g); 
    } 
}