帮助创建递归函数C#

时间:2009-08-21 20:02:55

标签: c# recursion

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

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

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

    }

编辑:

我认为如果我举例说明我想要做的事情会更有帮助。例如,如果工厂可以以“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

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

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

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

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

5 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:4)

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

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

  // Do stuff

  // Recurse
  GetNumberRec(start-1);
}

答案 2 :(得分:1)

我已经将你的例子重构为:

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

请确认这是正确的。

递归版本应如下所示:

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留给读者练习;)

答案 3 :(得分:0)

我之前提供了一个简单的C#递归函数here。 最顶层的功能最终会有每个排列的副本,因此它应该很容易适应您的需求..

答案 4 :(得分:0)

我意识到每个人都在这一点上打败了我,但这里是一个愚蠢的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);
    }
}