2012-07-31 10 views
6

Tengo estos para bucles.C++ Condensing anidado para bucles

// output all possible combinations 
for (int i1 = 0; i1 <= 2; i1++) 
    { 
     for (int i2 = 0; i2 <= 2; i2++) 
      { 
       for (int i3 = 0; i3 <= 2; i3++) 
        { 
         for (int i4 = 0; i4 <= 2; i4++) 
          { 
           for (int i5 = 0; i5 <= 2; i5++) 
            { 
             for (int i6 = 0; i6 <= 2; i6++) 
              { 
               for (int i7 = 0; i7 <= 2; i7++) 
                { 
                 //output created words to outFile 
                 outFile 
                 << phoneLetters[n[0]][i1]<< phoneLetters[n[1]][i2] 
                 << phoneLetters[n[2]][i3]<< phoneLetters[n[3]][i4] 
                 << phoneLetters[n[4]][i5]<< phoneLetters[n[5]][i6] 
                 << phoneLetters[n[6]][i7] 
                 << " "; 

                 if (++count % 9 == 0) // form rows 
                  outFile << std::endl; 
                 } 
               } 
             } 
           } 
         } 
       } 
     } 

Se ve horrible, pero estoy demasiado de un Novato saber por dónde empezar en lo que respecta a la condensación de ellos.

¿Alguien puede darme un puntero o dos para que pueda hacer que este código sea un poco más ordenado?

+13

Wow ... Esto es una obra de arte ... – Mysticial

+0

Me gustaría volver a escribir esto por lo que utiliza el menor número de bucles posible – frankV

+3

Sería bastante trivial convertir esto en una función recursiva donde cada llamada recursiva se acumula el siguiente valor, y cuando tenga suficientes valores, imprima el número. De forma alternativa, conserve un solo contador en ejecución y conviértalo en base 3 (o calcule sus componentes de base 3). –

Respuesta

6

Está indexando 0, 1 y 2 en siete niveles. Esto puede no ser muy eficiente, pero ¿qué tal esto:

int i1, i2, i3, i4, i5, i6, i7; 
int j; 

for (int i = 0; i < 2187; i++) 
{ 
    // 0 through 2186 represent all of the ternary numbers from 
    // 0000000 (base 3) to 2222222 (base 3). The following 
    // pulls out the ternary digits and places them into i1 
    // through i7. 

    j = i; 

    i1 = j/729; 
    j = j - (i1 * 729); 

    i2 = j/243; 
    j = j - (i2 * 243); 

    i3 = j/81; 
    j = j - (i3 * 81); 

    i4 = j/27; 
    j = j - (i4 * 27); 

    i5 = j/9; 
    j = j - (i5 * 9); 

    i6 = j/3; 
    j = j - (i6 * 3); 

    i7 = j; 

    // print your stuff 
} 

O, basado en la sugerencia de user315052 en los comentarios:

int d[7]; 

for (int i = 0; i < 2187; i++) 
{ 
    int num = i; 
    for (int j = 6; j >= 0; j--) 
    { 
     d[j] = num % 3; 
     num = num/3; 
    } 

    // print your stuff using d[0] ... d[6]] 
} 
+0

Bastante los cueros. – Puppy

+3

Usaría 'j% = X' en lugar de la resta/multiplicación. Si comienza a poblar el 7mo término primero, puede anular las constantes simplemente usando 3. Si cambia 'i' en una matriz, se convierte en un ciclo bastante simple para calcular los términos como una mod por 3, div por 3 en cada iteración. – jxh

+0

Edité mi respuesta para reflejar la sugerencia de user315052. Muy buena idea! – John

2

En el caso general, se puede usar la recursividad:

template <typename Stream, typename Iterator> 
void generateNumbers(Stream& stream, Iterator begin, Iterator end) { 
    if (end - begin == 7) { 
    for (Iterator p = begin; p < end; p++) { 
     stream << phoneLetters[n[*p]][*p]; 
    } 
    stream << " "; 
    } else { 
    for (*end = 0; *end <= 2; ++*end) 
     generateNumbers(stream,begin,end+1); 
    if (end - begin == 6) 
     stream << std::endl; 
    } 
} 

que se puede llamar, ya sea mediante el uso de un vector o una matriz de tampón C a secas (ambos con tamaño suficiente).

Por ejemplo:

std::vector<int> buf(7,0); 
generateNumbers(std::cout,buf.begin(),buf.begin()); 
// or 
int buf2[7]; 
generateNumbers(std::cout,buf2,buf2); 

Pero si sus valores son binarios, PBrando 's respuesta es mejor.

2

veo James McNellis ya se comentó esta solución, pero aquí está:

void phone_combo(int n[], int i[], int d, ostream &ofile, int &count) { 
    if (d == 7) { 
     //output created words to outFile 
     ofile 
     << phoneLetters[n[0]][i[0]]<< phoneLetters[n[1]][i[1]] 
     << phoneLetters[n[2]][i[2]]<< phoneLetters[n[3]][i[3]] 
     << phoneLetters[n[4]][i[4]]<< phoneLetters[n[5]][i[5]] 
     << phoneLetters[n[6]][i[6]] 
     << " "; 
     if (++count % 9 == 0) // form rows 
      ofile << std::endl; 
     } 
     return; 
    } 
    for (i[d] = 0; i[d] <= 2; i[d]++) { 
     phone_combo(n, i, d+1, ofile, count); 
    } 
} 

int i[7]; 
phone_combo(n, i, 0, outFile, count); 
0

Hubo una respuesta publicada anteriormente que redujo esto a un único bucle pero se eliminó por algún motivo.

for(int i(0); i!= 2187; ++i) 
{ 
    outFile 
    << phoneLetters[n[0]][(i >> 6) & 0x01]<< phoneLetters[n[1]][(i >> 5) & 0x01] 
    << phoneLetters[n[2]][(i >> 4) & 0x01]<< phoneLetters[n[3]][(i >> 3) & 0x01] 
    << phoneLetters[n[4]][(i >> 2) & 0x01]<< phoneLetters[n[5]][(i >> 1) & 0x01] 
    << phoneLetters[n[6]][i & 0x01] 
    << ' '; 

    if (++count % 9 == 0) // form rows 
     outFile << '\n'; 
} 

Esto solo funcionará si conoce el número exacto de iteraciones necesarias para calcular cada posible permutación.