2012-01-15 10 views
2

配列を考えるとa[i],i=0,1,...,ggは任意の数値であり、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の3つの言語がありますが、どれを使用しようとしていますか? –

+0

任意の言語を歓迎します。 –

答えて

1

再帰はこれを解決するための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

+0

私は反復解を追加しました。 – arx

+0

この入れ子関数は素晴らしいです。ありがとう、イーサン。 –

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にカウントしたいときには、ループのために余分に必要です。

代わりに、数字に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); 
    } 
} 
関連する問題