2010-01-24 18 views
12

Come potrei convertire questo codice per avere n annidati per i cicli:C#: N Cicli For

  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); 
         } 
        } 
       } 
      } 

Quindi, se num è 2 allora ci sarebbe solo 2 per i loop; io e j.

Questo NON è compito a casa e speravo di farlo in modo iterativo. Ogni Console.WriteLine() deve essere memorizzata come un elemento tutto insieme.

L'output di questo programma crea esponenti iperspasali dimensionali.

+5

È necessario rendere la funzione ricorsiva. Avere un argomento che specifica quanti cicli annidati devono ancora essere eseguiti. Quando è zero, fai il suo "thang". :-P Sarò felice di aiutarti ulteriormente una volta che avrò visto il tuo primo tentativo. :-) –

+4

Se si tratta di compiti a casa, si prega di etichettarlo così, altrimenti, ti aiuterò affermando il vostro caso aziendale. –

+1

Forse questo è il lavoro a casa? Cosa hai inventato finora? – womp

risposta

14

OK, si desidera una soluzione non ricorsiva che è parametrizzato in num e ha un numero costante di cicli annidati, sì?

Ecco uno schizzo di un metodo che lo fa. La compilazione dei dettagli è lasciata come esercizio.

In primo luogo, presumo che tu abbia un tipo immutabile "Vector" che può essere una tupla 0, 1-tupla, 2-tupla, 3-tupla, ... n-tupla.

Il metodo accetta la dimensione del vettore e restituisce una sequenza di vettori di tale dimensione.

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; 
    } 
} 

Là. Il problema è ora ridotto a due problemi minori:

1) Dato un vettore di dimensione num, è l'ultimo vettore nella sequenza?

2) In caso contrario, qual è il vettore successivo?

Dovrebbe essere abbastanza semplice calcolare quale sia il vettore successivo a quello attuale: aumentare il valore dell'ultimo slot. Se questo lo rende troppo grande, impostalo su zero e aumenta il valore dello slot precedente. Ripeti fino a quando non hai trovato la cosa che deve essere aumentata.

Ha senso?

+1

Il "rendimento in rendimento" era quello che stavo cercando. Non riuscivo proprio a ricordare come si chiamava e non riuscivo a capire come descriverlo a google. – Ames

+0

@Ames: per riferimento futuro il concetto è quello degli iteratori. cf. http://msdn.microsoft.com/en-us/library/dscyy5s0.aspx. – jason

1

si Assumendo la tua parola che non si tratta di compiti a casa, vedere sotto:

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, devi usare la ricorsione per gli scenari in cui è stato annidati i cicli in cui il numero di cicli annidati è sconosciuta al momento della compilazione . Qualcosa con l'idea di:

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. non sta usando std. e la domanda è codificata C#. +1 per codice piccolo. – Behrooz

+0

Richiede alcune modifiche semantiche minori per fare lo stesso del codice nella domanda, ma +1. – dtb

+0

Suppongo che sia una domanda a casa. Non volevo scrivere tutto, ma l'idea di fare cose del genere. –

0

In alternativa alla manipolazione separata delle cifre, come avviene nelle soluzioni ricorsive e in quelle che utilizzano un vettore <, è possibile fare affidamento sulle rappresentazioni della macchina e sull'aritmetica. Non è più veloce se è necessario esaminare ogni cifra ogni volta attraverso il ciclo, ma se si sta implementando un iteratore, si ridurrà lo spazio di archiviazione all'interno dell'iteratore e, se non si utilizza ogni singolo valore, potrebbe anche migliorare la tua efficienza. In ogni caso, è un approccio equivalente interessante. Qui va ...

Innanzitutto pensa al caso un po 'più generale in cui sono presenti i cicli nidificati n, ognuno dei quali conta da 0 a num. In questo caso, stai essenzialmente contando da 0 a num^n - 1 nel numero di base.Così si può fare qualcosa di simile:

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. 
} 

Nota che:

  • Se nessun tipo intero nativo è abbastanza grande per la vostra applicazione, quindi si dovrà utilizzare una sorta di vasta classe intero. Ciò ridurrà l'efficienza della memoria e incrementerà le parti, anche se forse non tanto quanto usare un vettore di lunghezza num.
  • Se si guarda ogni cifra ogni volta, quindi è necessario un vettore di cifre e non si è ottenuto nulla. Questo è davvero molto utile quando non guardi tutte le cifre ogni volta.
  • Tutti i divisori devono essere precalcolati, quindi è necessario mantenere un vettore per quello!

In ogni caso, per una particolare domanda, tu non vuoi contare fino a num ogni volta, si voleva contare fino a num - (the sum of the already decided digits). Il modo più semplice per spiegare ciò è semplicemente inserendo una condizione appropriata continue nei propri loop. Qui si è con alcuni valori sostituiti in per quando n=2 e 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 
    } 
} 

(Nel caso in cui non è ovvio, io non significa che si dovrebbe effettivamente utilizzare 100 e 10 nel codice, questo è solo un esempio illustrativo .)

È possibile rendere questo più efficiente calcolando quanto incrementare x di, o riducendo l'intervallo di x e quindi mappando direttamente al sottospazio anziché all'intero spazio. (Ma in 2-d e 3-d stai usando esattamente la metà dei valori possibili, in modo che il lavoro extra ti possa solo accelerare di 2. Penso che sia lo stesso quando n> 3, ma sono troppo pigro per capirlo in questo momento, mi spiace!)

Problemi correlati