所以我在课堂上复习,我似乎无法理解它。有什么建议可以帮助描绘这个过程吗?
从样本测试中我做:
class Q4
{
public static void main(String[] args)
{
f(3);
}
public static void f(int x)
{
if (x > 0)
{
System.out.println(x);
f(x-1);
System.out.println(x);
f(x-1);
}
System.out.println("bert");
}
}
我看到输出但我不明白为什么它是输出。 谢谢
答案 0 :(得分:4)
考虑递归的好方法是从基本情况开始,然后看看当您一次应用递归步骤时会发生什么。< / p>
此处的基本案例是x <= 0
。 f(0)
的输出是多少?我们可以直接看到这一点,因为永远不会输入if
语句。基本案例输出是:
bert
现在让我们看看f(1)
会发生什么。当x
为1时,代码会输入if
语句并最终调用f(0)
两次。如果在函数体中用1
替换x
,您将看到执行以下语句:
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
很明显println
语句的作用是什么,但两个f(0)
调用呢?好吧,我们知道f(0)
打印了什么,因为我们已经分析了基本情况。 f(0)
打印bert
。所以上面这些行的输出是:
1 // System.out.println(1);
bert // f(0);
1 // System.out.println(1);
bert // f(0);
bert // System.out.println("bert");
如果您对f(2)
应用相同的分析,您会看到它执行:
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
如果我们在调用f(1)
的两个地方替换f(1)
的输出,我们会得到:
2 // System.out.println(2);
1 // f(1);
bert
1
bert
bert
2 // System.out.println(2);
1 // f(1);
bert
1
bert
bert
bert // System.out.println("bert");
最后,f(3)
执行:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
代入f(2)
的输出,我们得到:
3 // System.out.println(3);
2 // f(2);
1
bert
1
bert
bert
2
1
bert
1
bert
bert
bert
3 // System.out.println(3);
2 // f(2);
1
bert
1
bert
bert
2
1
bert
1
bert
bert
bert
bert // System.out.println("bert");
答案 1 :(得分:2)
通过查看f
和x
,我们可以看到f
在这些情况下会做些什么。
f(3)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
f(2)
表示:
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
f(1)
表示:
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
f(0)
表示:
System.out.println("bert");
因此,将所有内容放在一起意味着我们正在减少数字的交叉输出并"bert"
。要查看每个数字或"bert"
来自哪里,您需要逐步执行递归调用以查看正在发生的事情。
例如,您最后会在一行中以多个"bert"
字符串结尾,但这是因为对f
的每次调用都以打印"bert"
结束。
答案 2 :(得分:0)
浏览纸上的代码。
f(3):
"3"
f(3-1) = f(2):
"2"
f(2-1) = f(1):
"1"
f(1-1) = f(0):
"bert"
"1"
f(1-1) = f(0):
"bert"
f(2-1) = f(1):
"1"
//...
答案 3 :(得分:0)
每次调用f(x-1)
时,都会创建f
的新本地范围,并且仅在该本地范围内可以使用名为x
的新本地变量:
调用f(3)
会创建一个新的本地范围,其中局部变量x
初始化为值3.让我们调用这个新的本地范围LS1
。单步执行此方法,我们可以看到3 > 0
为真,因此该方法打印出3
(首次调用System.out(x)
。
然后该方法调用自身,但传递的值为x-1。 JVM在这里做的第一件事是计算x-1,即2。注意它没有将结果赋给x
;我们称之为x
的范围中的变量LS1
仍为3.
它的作用是调用f(2)。这将创建一个带有名为x的局部变量的新本地范围。让我们调用这个新的本地范围LS2
。在LS2中,我们无法从LS1访问任何变量。 LS2有自己的一组局部变量 - 为LS2分配的内存中的新块与LS1的不同。 LS2中的局部变量x现在初始化为值。
同样,我们现在可以逐步完成f
以跟进流程。系统打印出2
,然后计算x-1
(等于1)并调用f(1)
。同样,在调用f(1)
时,会创建一个新的本地范围(让我们称之为LS3
),并为其局部变量分配另一个新的内存块。
LS3
中x的值初始化为1,方法继续。它打印出1,然后调用f(0)
。这将创建一个新的局部作用域(让我们称之为LS4
),并为其局部变量分配一个新的内存块。 x
中的LS4
初始化为0.单步执行f
,我们发现0 > 0
为false,因此会忽略代码块。打印出bert
并退出该方法。
现在销毁本地作用域LS4
并将其内存块(包含其本地变量)释放回堆中。控制现已回落到我们称之为LS3
的局部范围。回顾过去,我们可以看到x
中变量LS3
的最后一个值是1.下一条说明打印出来,因此打印出1
,然后打印出来{{ 1}}然后退出方法。
退出现在会破坏我们称之为bert
的本地范围。控制流回退到我们称为LS3
的本地范围。 LS2
中的变量x
设置为LS2
,因此会打印2
,然后是2
。
方法退出,销毁bert
并退回LS2
。 LS1
中的x
为LS1
,因此会打印3
,然后是3
。方法退出,程序结束。
希望一切都有意义!
修改强>
对不起,我错过了对bert
的第二次打电话,在那一刻,同样的事情再次发生了;创建一个新的范围并重复该方法。
答案 4 :(得分:-1)
请参阅Recursion是一种方法调用,其中同一方法调用自身 就像你的代码一样:
public static void f(int x)
{
if (x > 0)
{
System.out.println(x);
f(x-1); //at this point it will call itself as f(2)
System.out.println(x);
f(x-1);
}
System.out.println("bert");
}
它会继续调用自己,直到if条件为真。您需要了解的主要内容是方法调用的堆栈情况,无论它是否递归。
答案 5 :(得分:-1)
private String returnType(int t, String[] s) <- return type recursion example
{
String arrayed = s[t];
if (t == 0) // <--if 0
return " " + arrayed;
else
return arrayed + returnType(t - 1, s); <--if != 0 return value and then call itself again with the value -1.
}
当它达到0时返回数组。这将通过String [] s,并将所有字符串并排放在一个字符串中