我一直在四处寻找练习我的递归,但是我已经完成了在codingBat和其他一些方面的练习问题。如果您有更多建议,请随时评论!
我的问题是您如何确定何时可以简单地将方法转换为递归方法,即使您必须或可以更改参数?
所需的递归方法的元素是需要的基本情况,它认为递归的结束,以及循环或不循环的原因(恢复到基本情况)。我可能遗漏了递归方法的其他重要方面吗?
我发现的递归方法的一个例子(但尚未解决以便递归)如下所示。它来自codingBat,我不是要求任何人纠正我的代码。它只是一个可以转换的方法的例子,我发现了。我会搞清楚的。
编辑为答案。由于混淆删除了示例。 编写递归方法时需要注意的要求:
答案 0 :(得分:5)
基本上,递归可以模拟每个循环,所以可以为包含循环的每个方法创建一个递归方法 - 然而不能保证递归版本将完成(因为您的循环版本可能使用状态来缓存结果,而您的递归版本没有)或甚至运行(因为您可能会获得StackOverflowError
- 如何拟合)。
编辑:请注意,即使使用直接递归也可能导致堆栈溢出,有一种技术可以解决这个问题,即trampolining(文章适用于python,但也适用于Java 8的lambdas)。
编辑2:请注意迭代和递归解决方案之间的关系是由Church-Turing - 猜想引起的。
答案 1 :(得分:1)
总是可以将循环转换为递归(但不是相反):
// this is a general loop
for ( init(); loopCondition(); step() )
body();
// this is the general recursion of such a loop
function rec(recursionCondition, body, step) {
if(recursionCondition()) {
body();
step();
rec(recursionCondition, body, step);
}
}
// and don't forget to initialise at the calling level:
init();
rec(loopCondition, body, step);
例如
for(int i = 0; i < length; ++i)
doStuffOn(i);
function doStuffRec(int i, int length) {
if(i < length) { // recursionCondition
doStuffOn(i); // body
int nextI = i + 1; // step
doStuffRec(nextI, length);
}
}
// calling level (initialisation of i)
doStuffRec(0, length);
答案 2 :(得分:1)
基本上,您可以编写以递归或迭代方式循环的每个方法。你只需要一个条件来阻止循环。
有时,方法比迭代更容易实现递归。但值得注意的是运行时。
long fibonacci(long Parameter) {
if(Parameter <=1)
return 1;
else
return fibonacci(Parameter-1)+fibonacci(Parameter-2);
}
现在尝试为n=40
找到这个,这需要很长时间。为什么?因为运行时复杂性是指数级的。意味着计算需要更长的时间。
将此与iterativ实现进行比较:
long fibonacciIterativ(long Parameter) {
int a=1, b=1;
for(int i=1; i<Parameter;i++) {
a = a+b;
b = a-b;
}
return a;
}
这里运行时复杂度是线性的,意味着运行时随输入线性增长。 (IIRC甚至有一个公式的解决方案,因此运行时间为O(1),几乎是即时的)。
因此对于某些事情来说,递归函数比迭代更容易编写,有时反过来。但是通过使用递归函数,您必须注意运行时!