Java 有人能帮我理解递归吗?
所以我在课堂上复习了递归,我似乎无法集中注意力。有什么建议可以帮助描述这个过程吗 从我正在做的样本测试中:Java 有人能帮我理解递归吗?,java,recursion,Java,Recursion,所以我在课堂上复习了递归,我似乎无法集中注意力。有什么建议可以帮助描述这个过程吗 从我正在做的样本测试中: class Q4 { public static void main(String[] args) { f(3); } public static void f(int x) { if (x > 0) { System.out.println(x);
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");
}
}
我看到了输出,但我不明白为什么它是输出。
谢谢通过查看
f
和x
我们可以看到f
在这些情况下会做什么
f(3)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
f(2)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
f(1)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
f(0)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
所以把所有的东西放在一起意味着我们得到的是递减的交错输出和“bert”
。要查看每个数字或“bert”
来自何处,您需要逐步执行递归调用以查看发生了什么
例如,您将以一行中的几个
“bert”
字符串结尾,但这是因为每次调用f
都会以打印“bert”
结束,通过查看f
和x
我们可以看到f
在这些情况下会做什么
f(3)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
f(2)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
f(1)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
f(0)
表示:
System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");
System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");
System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");
System.out.println("bert");
所以把所有的东西放在一起意味着我们得到的是递减的交错输出和“bert”
。要查看每个数字或“bert”
来自何处,您需要逐步执行递归调用以查看发生了什么
例如,您将以一行中的几个
“bert”
字符串结尾,但这是因为对f
的每次调用都以打印“bert”结束。考虑递归的一个好方法是从基本情况开始,然后查看每次应用一个递归步骤时会发生什么
基本情况:f(0)
这里的基本情况是当x考虑递归的一个好方法是从基本情况开始,然后看看每次应用递归步骤时会发生什么
基本情况:f(0)
这里的基本情况是,xSee是一个方法调用,其中相同的方法调用自身。
因此,在您的代码中:
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条件为真。您需要了解的最主要的事情是方法调用的堆栈情况,无论它是递归的还是非递归的。请参阅相同方法调用自身的方法调用。
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.
}
因此,在您的代码中:
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条件为真。您需要了解的最主要的事情是方法调用的堆栈情况,无论它是否是递归的。private String returnType(int t,String[]s)private String returnType(int t,String[]s)在纸上浏览代码
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.
}
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"
//...
在纸上浏览代码
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"
//...
每次调用f(x-1)
时,都会为f
创建一个新的局部范围,并且名为x
的新局部变量仅在该局部范围内可用:
调用f(3)
创建一个新的局部范围,其中局部变量x
被初始化为值3。让我们把这个新的局部作用域称为LS1
。通过这个方法,我们可以看到3>0
是正确的,因此该方法打印出3
(首先调用System.out(x)
)
然后该方法调用自身,但传递一个值x-1。JVM在这里做的第一件事是计算x-1,即2。注意,它没有将结果分配给x
;我们调用的LS1
范围内的变量x
仍然是3。
它所做的是调用f(2)。这将使用一个名为x的局部变量创建一个新的局部作用域。让我们调用这个新的局部作用域LS2
。在LS2中,我们无法从LS1访问任何变量。LS2有自己的局部变量集-内存中为LS2分配的新块与为LS1分配的块不同。LS2中的局部变量x现在用一个值初始化共2人
同样,我们现在可以逐步通过f
来遵循流程。系统打印出2
,然后计算x-1
(等于1),然后调用f(1)
。再次,在调用f(1)
时,创建了一个新的局部范围(我们称之为LS3
),并为其局部变量分配另一个新内存块
LS3
中x的值被初始化为1,该方法继续。它打印出1,然后调用f(0)
。这将创建一个新的局部作用域(我们称之为LS4
)为其局部变量分配新的内存块。LS4
中的x
被初始化为0。通过f
单步执行,我们发现0>0
为false,因此忽略了代码块。bert
被打印出来,方法退出
局部作用域LS4现在被销毁,其内存块(包含其局部变量)被释放回堆。控件现在已回落到我们称之为LS3
的本地作用域。回过头来看,我们可以看到LS3
中变量x
的最后一个值是1。下一条指令指示打印该值,因此打印1
,然后打印bert
,然后退出该方法
现在退出会破坏我们称为LS3
的局部作用域。控制流会返回到我们称为LS2
的局部作用域。LS2
中的变量x
被设置为2
,因此打印2
,然后打印bert
方法退出,销毁LS2
并返回LS1
中的x
,LS1
是3
,因此打印3
,然后打印bert
。方法退出,程序完成
希望一切都有意义
编辑