帮助创建递归函数 C#

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1313969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:01:26  来源:igfitidea点击:

Help with Creating a Recursive Function C#

c#recursion

提问by Irwin M. Fletcher

I am creating a forecasting application that will run simulations for various "modes" that a production plant is able to run. The plant can run in one mode per day, so I am writing a function that will add up the different modes chosen each day that best maximize the plant's output and best aligns with the sales forecast numbers provided. This data will be loaded into an array of mode objects that will then be used to calculate the forecast output of the plant.

我正在创建一个预测应用程序,它将为生产工厂能够运行的各种“模式”运行模拟。工厂每天可以以一种模式运行,所以我正在编写一个函数,它将每天选择的不同模式相加,以最大限度地提高工厂的产量,并与所提供的销售预测数字最好地保持一致。该数据将加载到模式对象数组中,然后用于计算工厂的预测输出。

I have created the functions to do this, however, I need to make them recursive so that I am able to handle any number (within reason) of modes and work days (which varies based on production needs). Listed below is my code using for loops to simulate what I want to do. Can someone point me in the right direction in order to create a recursive function to replace the need for multiple for loops?

我已经创建了执行此操作的函数,但是,我需要使它们递归,以便我能够处理任意数量(在合理范围内)的模式和工作日(根据生产需求而变化)。下面列出的是我使用 for 循环来模拟我想要做的事情的代码。有人可以指出我正确的方向以创建一个递归函数来代替对多个 for 循环的需求吗?

Where the method GetNumbers4 would be when there were four modes, and GetNumbers5 would be 5 modes. Int start would be the number of work days.

当有四种模式时,方法 GetNumbers4 的位置,而 GetNumbers5 将是 5 个模式。int start 将是工作日数。

  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:

编辑:

I think that it would be more helpful if I gave an example of what I was trying to do. For example, if a plant could run in three modes "A", "B", "C" and there were three work days, then the code will return the following results.

我认为如果我举一个我正在尝试做的事情的例子会更有帮助。例如,如果工厂可以在“A”、“B”、“C”三种模式下运行并且有三个工作日,那么代码将返回以下结果。

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

The series of numbers represent the three modes A B C. I will load these results into a Modes object that has the corresponding production rates. Doing it this way allows me to shortcut creating a list of every possible combination; it instead gives me a frequency of occurrence.

这一系列数字代表三种模式 AB C。我将这些结果加载到具有相应生产率的 Modes 对象中。这样做可以让我快捷地创建每个可能组合的列表;相反,它给了我一个发生频率。

Building on one of the solutions already offered, I would like to do something like this.

基于已经提供的解决方案之一,我想做这样的事情。

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

Thanks to everyone who have already provided input.

感谢所有已经提供意见的人。

采纳答案by Jimmy

Calling GetNumber(5, x) should yield the same result as GetNumber5(x):

调用 GetNumber(5, x) 应该产生与 GetNumber5(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;
    }
}

回答by Brian

I previously offered a simple C# recursive function here. The top-most function ends up having a copy of every permutation, so it should be easily adapted for your needs..

我以前在这里提供了一个简单的 C# 递归函数。最顶层的函数最终拥有每个排列的副本,因此它应该很容易适应您的需求。

回答by dahlbyk

A recursive function just needs a terminating condition. In your case, that seems to be when startis less than 0:

递归函数只需要一个终止条件。在您的情况下,这似乎start是小于 0 的时间:

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

  // Do stuff

  // Recurse
  GetNumberRec(start-1);
}

回答by dtb

I've refactored your example into this:

我已将您的示例重构为:

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

Please verify this is correct.

请确认这是正确的。

A recursive version should then look like this:

递归版本应该如下所示:

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

FormatCountersis left as an exercise to the reader ;)

FormatCounters留给读者作为练习;)

回答by Brent Writes Code

I realize that everyone's beaten me to the punch at this point, but here's a dumb Java algorithm (pretty close to C# syntactically that you can try out).

我意识到在这一点上每个人都击败了我,但这里有一个愚蠢的 Java 算法(在语法上非常接近 C#,您可以尝试一下)。

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