2010-01-24 11 views
12

¿Cómo podría convertir el código para tener n para los bucles anidados:C#: N Para Loops

  int num = 4; 

      for (int i = 0; i <= num; i++) 
      { 
       for (int j = 0; j + i <= num; j++) 
       { 
        for (int k = 0; i + j + k <= num; k++) 
        { 
         for (int l = 0; i + j + k + l <= num; l++) 
         { 
          Console.WriteLine(i + " " + j + " " + k + " " + l); 
         } 
        } 
       } 
      } 

Así que si num es 2 entonces no serían solamente 2 de los bucles; i y j.

Esto NO es tarea y esperaba hacerlo de forma iterativa. Cada Console.WriteLine() debe almacenarse como un elemento al mismo tiempo.

El resultado de este programa crea exponentes hyperspase n dimensionales.

+5

Necesita hacer que su función sea recursiva. Tenga un argumento que especifique cuántos bucles anidados todavía quedan para ejecutarse. Cuando es cero, hazlo "thang". :-P Estaré encantado de ayudarte aún más una vez que vea tu primer intento de esto. :-) –

+4

Si esto es tarea, por favor etiquételo así, de lo contrario, se ayudará exponiendo su caso de negocio. –

+1

¿Es acaso esta tarea? ¿Qué has pensado hasta ahora? – womp

Respuesta

14

OK, que desea una solución no recursiva que es parametrizado en num y tiene un número constante de bucles anidados, sí?

Aquí hay un boceto de un método que hace eso. Llenar los detalles se deja como un ejercicio.

En primer lugar, supongo que tiene un tipo inmutable "Vector" que puede ser un 0-tupla, 1-tupla, 2-tupla, 3-tupla, ... n-tupla.

El método admite el tamaño del vector y devuelve una secuencia de vectores de ese tamaño.

IEnumerable<Vector> MakeVectors(int num) 
{ 
    Vector current = new Vector(num); // make an all-zero vector with num items. 
    while(true) 
    { 
     yield return current; 
     Vector next; 
     bool gotAnother = GetNextVector(current, out next); 
     if (!gotAnother) break; 
     current = next; 
    } 
} 

There. El problema ahora se ha reducido a dos problemas más pequeños:

1) Dado un vector de tamaño num, ¿es el último vector de la secuencia?

2) En caso negativo, ¿cuál es el siguiente vector?

Debería ser bastante sencillo determinar cuál es el siguiente vector actual: aumentar el valor de la última ranura. Si eso lo hace demasiado grande, ajústelo a cero y aumente el valor de la ranura anterior. Repita hasta que encuentre lo que se va a aumentar.

¿Tiene sentido?

+1

El 'rendimiento de retorno' era lo que estaba buscando. Simplemente no podía recordar cómo se llamaba y no pude encontrar la forma de describirlo a google. – Ames

+0

@Ames: para referencia futura, el concepto es el de iteradores. cf. http://msdn.microsoft.com/en-us/library/dscyy5s0.aspx. – jason

1

que toma en su palabra de que esto no es tarea, ver más abajo:

public void LoopRecursively(Stack<int> valuesSoFar, int dimensions) 
    { 
     for (var i = 0; SumOf(valuesSoFar) + i <= dimensions; i++) 
     { 
      valuesSoFar.Push(i); 
      if (valuesSoFar.Count == dimensions) 
      { 
       Console.WriteLine(StringOf(valuesSoFar)); 
      } 
      else 
      { 
       LoopRecursively(valuesSoFar, dimensions); 
      } 
      valuesSoFar.Pop(); 
     } 
    } 

    private int SumOf(IEnumerable<int> values) 
    { 
     return values.Sum(x => x); 
    } 

    private string StringOf(IEnumerable<int> values) 
    { 
     return string.Join(" ", values.Reverse().Select(x => x.ToString()).ToArray()); 
    } 
11

Normalmente, tendrá que utilizar la recursividad para escenarios donde han anidado bucles de las que se desconoce el número de bucles anidados en tiempo de compilación . Algo con la idea de:

void func(const vector<int> &times, int depth) { 
    if (depth == times.size()) return; 
    for (int i = 0; i < times[depth]; ++i) { 
     cout << depth; 
     func(times, depth + 1); 
    } 
} 
+0

@mehrdad. él no está usando std. y la pregunta está etiquetada C#. +1 para código pequeño. – Behrooz

+0

Necesita algunas modificaciones semánticas menores para hacer lo mismo que el código en la pregunta, pero +1. – dtb

+0

Supongo que es una pregunta de tarea. No quise escribir todo, excepto la idea de hacer cosas así. –

0

Como alternativa a la manipulación de los dígitos por separado, como se hace en las soluciones recursivas y las que usan un Vector <>, puede confiar en las representaciones de la máquina y la aritmética. Esto no es más rápido si necesita examinar cada dígito cada vez a través del ciclo, pero si está implementando un iterador, reducirá su espacio de almacenamiento dentro del iterador, y si no está utilizando todos los valores, entonces también puede Mejora tu eficiencia. En cualquier caso, es un enfoque equivalente interesante. Aquí va ...

Primero piense en el caso un poco más general en el que tiene n bucles anidados, cada uno de los cuales cuenta de 0 a num. En ese caso, básicamente estás contando de 0 a num^n - 1 en la base núm.Así que usted puede hacer algo como esto:

for(int x=0; x<(num^n); x++) 
{ 
    int digit_0 = x % num; 
    int digit_1 = (x/num) % num; 
    int digit_2 = (x/num^2) % num; 
    // etc. 
} 

Tenga en cuenta que:

  • Si ningún tipo entero nativa es lo suficientemente grande como para su aplicación, entonces usted tendrá que usar algún tipo de gran clase entero. Esto reducirá la eficiencia del almacenamiento e incrementará las partes, aunque tal vez no tanto como usar un vector de longitud num.
  • Si realmente miras cada dígito cada vez, entonces necesitas un vector de dígitos, y no has ganado nada. Esto es realmente más útil cuando no está mirando todos los dígitos cada vez.
  • Todos los divisores deben estar precalculados, por lo que debe mantener un vector para eso.

De todos modos, para su pregunta en particular, que no desea contar con num cada vez, que quería contar hasta num - (the sum of the already decided digits). La forma más sencilla de dar cuenta de esto es simplemente colocando una condición continue apropiada en sus bucles. Aquí se está con algunos valores sustituidos en para cuando n=2 y num=10:

for(x=0; x<100; x++) // i.e. x < num*num 
{ 
    int ones = x%10; // i.e. x % num 
    int tens = (x/10) % 10; // i.e. (x/num) % num 

    if(ones + tens < 10) 
    { 
    // actually do work 
    } 
} 

(En caso de que no es obvio, no quiero decir que realmente debe utilizar 100 y 10 en el código, esto es sólo un ejemplo ilustrativo .)

Puede hacer que esto sea más eficiente al calcular cuánto aumentar x, o al reducir el rango de x y luego mapear directamente a su subespacio en lugar de a todo el espacio. (Pero en 2-dy 3-d está utilizando exactamente la mitad de los valores posibles, por lo que el trabajo adicional solo le daría una aceleración de 2. Creo que es lo mismo cuando n> 3, pero soy demasiado vago para entenderlo en este momento, lo siento!)