2009-08-21 19 views
1

Ich erstelle eine Prognoseanwendung, die Simulationen für verschiedene "Modi" ausführt, die eine Produktionsanlage ausführen kann. Die Anlage kann in einem Modus pro Tag betrieben werden, deshalb schreibe ich eine Funktion, die die verschiedenen Modi addiert, die jeden Tag ausgewählt werden, um die Leistung der Anlage am besten zu maximieren und sich am besten mit den angegebenen Umsatzvorhersagenummern auszurichten. Diese Daten werden in ein Array von Modusobjekten geladen, die dann zur Berechnung der prognostizierten Ausgabe der Anlage verwendet werden.Hilfe beim Erstellen einer rekursiven Funktion C#

Ich habe die Funktionen erstellt, um dies zu tun, jedoch muss ich sie rekursiv machen, so dass ich in der Lage bin, mit einer beliebigen Anzahl (innerhalb des Grundes) von Modi und Arbeitstagen (die je nach Produktionsanforderungen variiert). Im Folgenden finden Sie meinen Code, der for-Schleifen verwendet, um zu simulieren, was ich tun möchte. Kann mir jemand in die richtige Richtung zeigen, um eine rekursive Funktion zu erstellen, die die Notwendigkeit mehrerer For-Schleifen ersetzt?

Wo die Methode GetNumbers4 wäre, wenn es vier Modi gäbe, und GetNumbers5 wären 5 Modi. Int Start wäre die Anzahl der Arbeitstage.

private static void GetNumber4(int start) 
    { 
     int count = 0; 
     int count1 = 0;   

     for (int i = 0; 0 <= start; i++) 
     { 
      for (int j = 0; j <= i; j++) 
      { 

       for (int k = 0; k <= j; k++) 
       { 
        count++; 

        for (int l = 0; l <= i; l++) 
        { 
         count1 = l; 
        } 

        Console.WriteLine(start + " " + (count1 - j) + " " + (j - k) + " " + k); 
        count1 = 0; 
       } 

      } 
      start--; 

     } 
     Console.WriteLine(count); 

    } 

    private static void GetNumber5(int start) 
    { 
     int count = 0; 
     int count1 = 0; 

     for (int i = 0; 0 <= start; i++) 
     { 
      for (int j = 0; j <= i; j++) 
      { 

       for (int k = 0; k <= j; k++) 
       { 

        for (int l = 0; l <= k; l++) 
        { 
         count++; 
         for (int m = 0; m <= i; m++) 
         { 
          count1 = m; 
         } 
         Console.WriteLine(start + " " + (count1 - j) + " " + (j - k) + " " + (k - l) + " " + l); 
         count1 = 0; 
        } 

       } 

      } 
      start--; 

     } 
     Console.WriteLine(count); 

    } 

EDITED:

Ich denke, dass es hilfreich wäre, wenn ich ein Beispiel gegeben, was ich versuche zu tun. Wenn beispielsweise eine Anlage in drei Modi "A", "B", "C" ausgeführt werden kann und es drei Arbeitstage gibt, gibt der Code die folgenden Ergebnisse zurück.

3 0 0 
2 1 0 
2 0 0 
1 2 0 
1 1 1 
1 0 2 
0 3 0 
0 2 1 
0 1 2 
0 0 3 

Die Reihe von Zahlen stellen die drei Modi A B C I diese Ergebnisse in einem Modes Objekt laden wird, die die entsprechenden Produktionsraten aufweist. Auf diese Weise kann ich eine Liste aller möglichen Kombinationen erstellen. es gibt mir stattdessen eine Häufigkeit des Auftretens.

Aufbauend auf einer der bereits angebotenen Lösungen würde ich gerne so etwas tun.

//Where Modes is a custom classs 
    private static Modes GetNumberRecur(int start, int numberOfModes) 
    { 
     if (start < 0) 
     { 
      return Modes; 

     } 

     //Do work here 
     GetNumberRecur(start - 1); 
    } 

Vielen Dank an alle, die bereits zur Verfügung gestellt haben.

+2

Sie brauchen * nie * eine rekursive Funktion. Alles, was Sie rekursiv tun können, kann iterativ durchgeführt werden, einige Probleme eignen sich nur für die Rekursion, wie das Durchlaufen eines Dateisystems. –

+0

Warum zählt nicht1 irgendetwas? – Jimmy

+0

Count1 wird verwendet, um die Ergebnisse von der innersten for-Schleife an die console.writeline außerhalb der Schleife zu übergeben. –

Antwort

6

Aufruf GetNumber (5, x) sollte das gleiche Ergebnis wie GetNumber5 ergeben (x):

static void GetNumber(int num, int max) { 
    Console.WriteLine(GetNumber(num, max, "")); 
} 
static int GetNumber(int num, int max, string prefix) { 
    if (num < 2) { 
     Console.WriteLine(prefix + max); 
     return 1; 
    } 
    else { 
     int count = 0; 
     for (int i = max; i >= 0; i--) 
      count += GetNumber(num - 1, max - i, prefix + i + " "); 
     return count; 
    } 
} 
+0

Sie haben es absolut genagelt. Danke vielmals. –

+0

Um ehrlich zu sein, eine bessere Lösung würde beinhalten, dass GetNumber einen Iterator von int [] oder etwas liefert, so dass Ihre anderen Komponenten die Werte direkt übernehmen könnten. – Jimmy

0

Ich bot zuvor eine einfache C# rekursive Funktion here. Die oberste Funktion endet mit einer Kopie jeder Permutation, so sollte es leicht für Ihre Bedürfnisse angepasst werden.

4

Eine rekursive Funktion benötigt nur eine Abbruchbedingung. In Ihrem Fall scheint das zu sein, wenn start kleiner als 0:

private static void GetNumberRec(int start) 
{ 
    if(start < 0) 
    return; 

    // Do stuff 

    // Recurse 
    GetNumberRec(start-1); 
} 
1

ich Ihr Beispiel in diese Refactoring haben:

private static void GetNumber5(int start) 
{ 
    var count = 0; 

    for (var i = 0; i <= start; i++) 
    { 
     for (var j = 0; j <= i; j++) 
     { 
      for (var k = 0; k <= j; k++) 
      { 
       for (var l = 0; l <= k; l++) 
       { 
        count++; 

        Console.WriteLine(
         (start - i) + " " + 
         (i - j) + " " + 
         (j - k) + " " + 
         (k - l) + " " + 
         l); 
       } 
      } 
     } 
    } 

    Console.WriteLine(count); 
} 

Bitte überprüfen dies richtig ist.

Eine rekursive Version sollte dann wie folgt aussehen:

public static void GetNumber(int start, int depth) 
{ 
    var count = GetNumber(start, depth, new Stack<int>()); 
    Console.WriteLine(count); 
} 

private static int GetNumber(int start, int depth, Stack<int> counters) 
{ 
    if (depth == 0) 
    { 
     Console.WriteLine(FormatCounters(counters)); 
     return 1; 
    } 
    else 
    { 
     var count = 0; 
     for (int i = 0; i <= start; i++) 
     { 
      counters.Push(i); 
      count += GetNumber(i, depth - 1, counters); 
      counters.Pop(); 
     } 
     return count; 
    } 
} 

FormatCounters wird als Übung dem Leser überlassen;)

0

ich weiß, dass jeder mich auf den Stempel an diesem Punkt geschlagen hat, aber hier ist ein dummer Java-Algorithmus (ziemlich nah an C# syntaktisch t du kannst es ausprobieren).

import java.util.ArrayList; 
import java.util.List; 

/** 
* The operational complexity of this is pretty poor and I'm sure you'll be able to optimize 
* it, but here's something to get you started at least. 
*/ 
public class Recurse 
{ 
    /** 
    * Base method to set up your recursion and get it started 
    * 
    * @param start The total number that digits from all the days will sum up to 
    * @param days The number of days to split the "start" value across (e.g. 5 days equals 
    * 5 columns of output) 
    */ 
    private static void getNumber(int start,int days) 
    { 
     //start recursing 
     printOrderings(start,days,new ArrayList<Integer>(start)); 
    } 

    /** 
    * So this is a pretty dumb recursion. I stole code from a string permutation algorithm that I wrote awhile back. So the 
    * basic idea to begin with was if you had the string "abc", you wanted to print out all the possible permutations of doing that 
    * ("abc","acb","bac","bca","cab","cba"). So you could view your problem in a similar fashion...if "start" is equal to "5" and 
    * days is equal to "4" then that means you're looking for all the possible permutations of (0,1,2,3,4,5) that fit into 4 columns. You have 
    * the extra restriction that when you find a permutation that works, the digits in the permutation must add up to "start" (so for instance 
    * [0,0,3,2] is cool, but [0,1,3,3] is not). You can begin to see why this is a dumb algorithm because it currently just considers all 
    * available permutations and keeps the ones that add up to "start". If you want to optimize it more, you could keep a running "sum" of 
    * the current contents of the list and either break your loop when it's greater than "start". 
    * 
    * Essentially the way you get all the permutations is to have the recursion choose a new digit at each level until you have a full 
    * string (or a value for each "day" in your case). It's just like nesting for loops, but the for loop actually only gets written 
    * once because the nesting is done by each subsequent call to the recursive function. 
    * 
    * @param start The total number that digits from all the days will sum up to 
    * @param days The number of days to split the "start" value across (e.g. 5 days equals 
    * 5 columns of output) 
    * @param chosen The current permutation at any point in time, may contain between 0 and "days" numbers. 
    */ 
    private static void printOrderings(int start,int days,List<Integer> chosen) 
    { 
     if(chosen.size() == days) 
     { 
      int sum = 0; 
      for(Integer i : chosen) 
      { 
       sum += i.intValue(); 
      } 

      if(sum == start) 
      { 
       System.out.println(chosen.toString()); 
      } 
      return; 
     } 
     else if(chosen.size() < days) 
     { 
      for(int i=0; i < start; i++) 
      { 
       if(chosen.size() >= days) 
       { 
        break; 
       } 

       List<Integer> newChosen = new ArrayList<Integer>(chosen); 
       newChosen.add(i); 
       printOrderings(start,days,newChosen); 
      } 
     } 
    } 

    public static void main(final String[] args) 
    { 
     //your equivalent of GetNumber4(5) 
     getNumber(5,4); 

     //your equivalent of GetNumber5(5) 
     getNumber(5,5); 
    } 
} 
Verwandte Themen