Java递归 - 我这样做了吗?

时间:2014-06-08 21:53:27

标签: java recursion

我的工作是为此方法编写递归版本。根据我的理解,Recursion从一个基本调用开始(如果有东西然后返回),然后是一个展开回原始基础的else。就像从甲板开始一样,加入甲板然后从甲板上取下卡片,直到你回到原来的甲板上。 考虑到这一点。

public static long fact(int n)
{
    long result = 1;
    while(n > 0)
    {
         result = result * n;
         n = n - 1;
    }

    return result;
}

//我的递归版本:

public static void recFact(int n)
{
    if(n==0)
    {
        return n; // ir 0 it really doesn't matter right?
    }
    else
    {
        return recFact(n-1);
    }
}

这只是我出现的考试的一个示例测试问题,只是想确保我有一个递归的句柄。我做对了吗?如果不是我错过了什么?请不要回答问题的答案,只要告诉我我做错了什么,也许就更好的理解方法提出一些建议。

感谢。

6 个答案:

答案 0 :(得分:3)

您的递归版本没有乘法,并且对于任何输入它将返回零。所以不,你做得不对。

但是,递归版本会递归,所以你有这个想法!要了解出了什么问题,请完成一个非常简单的案例。

客户来电recFact(3)
这将返回给客户recFact(2)
哪个将返回到recFact(1)以上 哪个将返回到recFact(0)以上 哪个将返回到0以上。

出现两个主要问题:

  • 你的基本情况是错误的(零太低)
  • 你没有做任何乘法

不希望解决方案交给你的态度很好!希望这些指针能帮助你解决这个问题。

编辑:显然我误解了你的语法,你确实想要解决方案。

答案 1 :(得分:3)

不,这种递归解决方案不正确。

对于每个积极n,您只需返回rectFact(n-1),这将追索到0,此时它将返回。换句话说,您的函数将始终返回0。您错过了乘以当前nrectFact(n-1)的部分。另请注意,0!为1,而不是0:

public static int recFact(int n)
{
    if(n==0)
    {
        return 1;
    }
    else
    {
        return n * recFact(n-1);
    }
}

最后,由于if子句返回,else有点多余。当然,这并不影响方法的正确性,但恕我直言,没有它,代码看起来更清晰:

public static int recFact(int n)
{
    if(n==0)
    {
        return 1;
    }
    return n * recFact(n-1);
}

答案 2 :(得分:2)

任何递归函数都需要三件事:

  1. 终止条件:这告诉函数何时停止调用自身。这对于避免无限递归和避免堆栈溢出异常非常重要。

  2. 实际处理:您需要在每个功能中运行实际处理。在非递归的情况下,这是result = result * n您的递归版本中缺少此内容!

  3. 收集器/聚合器变量:您需要一些方法来存储您下面的递归调用的部分结果。因此,您需要一些方法来返回recFact的结果,以便您可以将其包含在调用链中更高的处理中。请注意,您说return recFact(n - 1)但在定义recFact中会返回void。这应该是int

答案 3 :(得分:1)

根据您的示例,您遗漏了return type的{​​{1}} recFact

同样int将始终返回0,因为您每次都不会将recFact乘以方法的递归调用。

答案 4 :(得分:0)

有两种方法可以编写递归例程。一个是"标准"我们都被教导的方式。这是一个入口点,必须首先检查递归链是否在末尾(escape子句)。如果是这样,它将返回"链的结尾"值并结束递归。如果不是最后,它会执行根据级别获取部分值所需的任何计算,然后调用自身将值传递给接近链末尾的下一个增量。

private final int InitialValue = 15;
System.out.println( "Fact(" + InitialValue + ") = " + recFact( InitialValue ) );

public int recFact( int val ){
    if( val < 2 ){
        return 1;
    }
    else{
        return recFact( val - 1 ) * val; // recursive call
    }
}

//Output: "Fact(15) = 2004310016"

在常规递归中,在每个级别维持部分答案,用于补充下一级别的答案。在上面的代码中,部分答案是val。首次调用时,此值为15。它取这个值并乘以Fact(14)的答案,为Fact(15)提供完整的答案。事实(14)得到了答案,将14乘以从事实(13)得到的答案,等等。

还有另一种称为尾递归的递归。这不同之处在于部分答案被传递到下一级而不是在每个级别维护。这听起来很复杂,但实际上,使递归过程更加简单。另一个区别是有两个例程,一个是非递归的,并设置递归例程。这是为了只为想要查看(并且只需要查看)

的用户维护标准API
answer = routine( parameter );

非递归例程提供了这个功能。它也是放置一次性代码(例如错误检查)的便利位置。请注意,在上面的标准例程中,如果用户传入的是-15而不是15,则例程可能会弹出。这意味着在生产代码中,必须进行这样的测试。但是每次进入例程时都会执行此测试,这意味着除了第一次之外,所有测试都将不必要地进行。此外,因为它必须返回一个整数值,它不能处理大于19的初始值,因为这将导致一个将溢出32位整数容器的值。

public static final int MaxFactorialSeq = 20;
private final int InitialValue = 15;
System.out.println( "Fact(" + InitialValue + ") = " + recFact( InitialValue ) );

public int recFact( int value ){
    if( value < 0 || value > MaxFactorialSeq ){
        throw new IllegalArgumentException(
                "Factorial sequence value " + value + " is out of range." );
    }
    return recFact( value, 1 ); // initial invocation
}

private int recFact( int val, int acc ){
    if( val < 2 ){
        return acc;
    }
    else{
        return recFact( val - 1, acc * val ); // recursive call
    }
}

//Output: "Fact(15) = 2004310016"

请注意,公共入口点包含范围检查代码。这只执行一次,递归例程不必进行此检查。然后它使用初始&#34;种子&#34;来调用递归版本。 1。

递归例程和以前一样,检查它是否在链的末尾。如果是这样,它返回,而不是像以前那样返回1,但是此时的累加器具有完整的答案。然后,调用链将回退到非递归例程中的初始入口点。没有进一步的计算,因为答案是在向下计算而不是向上计算的。

如果你走过它,标准递归的答案是通过序列15 * 14 * 13 * ... * 2 * 1达到的。通过尾递归,答案是通过序列1 * 15 * 14 * ... * 3 * 2达到的。当然,最终的答案是一样的。但是,在初始值为15的测试中,标准递归方法平均为0.044毫秒,尾递归方法平均为0.030毫秒。但是,几乎所有的时间差都是由于我在标准递归例程中检查边界这一事实。没有它,时间更接近(0.036到0.030),但当然,你没有错误检查。

并非所有递归例程都可以使用尾递归。但是,并非所有的递归例程都应该如此。不言而喻,任何递归函数都可以使用循环编写。而且一般应该是。但是像上面那样的因子函数永远不会超过19个级别,所以它们可以被添加到幸运的少数人中。

答案 5 :(得分:-1)

递归的问题在于,要理解递归,首先必须理解递归。

递归函数是一个调用自身的函数,或者调用最终再次调用第一个函数的函数。

你有正确的递归部分,因为你的函数调用自己,你有一个&#34;转义&#34;因此你不会得到无限递归(函数不能调用自身的原因)。

你的例子中缺少的是你正在进行的实际操作。

此外,你需要传递你的计数器和你所乘的值,而不是传递一个计数器,然后你需要返回所说的乘法值。

public static long recFact(int n, long val)
{
    if(n==1)
    {
        return val;
    }
    else
    {
        return recFact(n-1, val) * n;
    }
}