Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 有人能帮我理解递归吗?_Java_Recursion - Fatal编程技术网

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
。方法退出,程序完成

希望一切都有意义

编辑