Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.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 递归和Return关键字_Java_Recursion - Fatal编程技术网

Java 递归和Return关键字

Java 递归和Return关键字,java,recursion,Java,Recursion,我目前正在学习Java教程,目前正在学习递归 我有下面的代码,它计算传递给factorial方法的任何数字的阶乘 public class App { public static void main(String[] args) { //E.g 4! = 4*3*2*1(factorial 4) System.out.println(factorial(4)); } private static int factorial(int val

我目前正在学习Java教程,目前正在学习递归

我有下面的代码,它计算传递给factorial方法的任何数字的阶乘

public class App {
    public static void main(String[] args) {
        //E.g 4! = 4*3*2*1(factorial 4)
        System.out.println(factorial(4));

    }
    private static int factorial(int value){
        //System.out.println(value);
        if (value == 1){
            return 1;
        }
        return factorial(value - 1)*value;
    }
}
我很难理解这个部分

if (value == 1){
    return 1;
}
return factorial(value - 1)*value;
我的理解是return关键字只是终止该方法,和/或返回该方法声明的相同类型的值(即int、String等)

运行以下行时会发生什么情况

return factorial(value - 1)*value;
函数返回(值-1)*值的总和,这将给我

(3)*4 = 12
(2)*3 = 6
(1)*2 = 2
但是,
System.out.println(阶乘(4))给了我总共
24
。这个数字是如何从这个方法中推导出来的?没有变量来存储值的总和,那么程序在哪里存储它们呢?另外,如何从这些值中获取
24

(3)*4
(2)*3
(1)*2
虽然我知道
24
是从
4*3*2*1
派生出来的,但我不知道如何从上面计算出来

任何解释都将不胜感激。

您误解了

return factorial(value - 1)*value;
相乘的值是
factorial(值-1)
value
。换句话说,您可以这样重写它:

return (factorial(value - 1)) * value;
private static int factorial(int value){
    if (value == 1){
        return 1;
    }
    int a = factorial(value - 1);
    return a * value;
}
所以当你通过4级考试时,你会得到:

factorial(3) * 4;
这相当于

(factorial(2) * 3) * 4;
((factorial(1) * 2) * 3) * 4;
1 * 2 * 3 * 4;
这相当于

(factorial(2) * 3) * 4;
((factorial(1) * 2) * 3) * 4;
1 * 2 * 3 * 4;
这相当于

(factorial(2) * 3) * 4;
((factorial(1) * 2) * 3) * 4;
1 * 2 * 3 * 4;
其工作方式如下所示,如果使用调试器单步执行代码,您可以很容易地看到:

  • 对函数的第一次调用通过
    4
    。函数计算if,然后调用自身,传递
    3
    。(第一个函数调用的状态保留在堆栈上,因此,当此调用返回时,我们可以从我们停止的地方继续,现在我们已经有了函数调用的结果。这个“堆栈”抽象实际上不是理解递归所必需的。)

  • 第二个函数调用计算if并调用自身,传递
    2

  • 第三个函数调用计算if并调用自身,传递
    1
  • 第四个函数调用计算if并返回1
  • 然后,第三个函数调用继续,将刚刚返回的函数的返回值(
    1
    )与其参数的值(
    2
    )相乘,返回结果(
    2
  • 然后,第二个函数调用继续,将刚刚返回的函数的返回值(
    2
    )与其参数的值(
    3
    )相乘,返回结果(
    6
  • 然后,第一个函数调用继续,将刚刚返回的函数的返回值(
    6
    )与其参数的值(
    4
    )相乘,返回结果(
    24
  • 一些优化编译器会将递归调用更改为循环,但通常不可能将递归调用更改为固定表达式,如
    1*2*3*4
    ,因为在编译时,您通常不知道递归的深度

    如果您按照以下方式修改代码,然后使用调试器逐步完成,所有这些都将非常清楚:

    private static int factorial(int value){
        if (value == 1){
            return 1;
        }
        int recursiveResult = factorial(value - 1);
        return recursiveResult * value;
    }
    
    注意,对于每个递归调用,我们必须在堆栈上存储等待调用结果的“挂起”方法的状态。由于这个原因,如果一个方法递归地调用自己(或者一个方法链在相互递归中调用自己),堆栈就有可能变满。这称为堆栈溢出。这通常是由于函数中的错误逻辑导致递归循环:

    int stackOverflow() { return stackOverflow(); }
    
    这也可能是由于函数没有逻辑循环,但由于传递给它的数据而多次调用自身造成的。例如,递归函数在处理树数据结构时非常有用;如果树太高,可能会导致堆栈溢出。以下内容也会有一些论据,但不会有其他论据:

    void possibleStackOverflow(int arg) { if (arg == 0) return; possibleStackOverflow(arg - 1); }
    
    如果调用
    possibleStackOverflow(10)
    您可能很好,但是
    possibleStackOverflow(-1)
    将引发异常


    另外,由于VM实现的限制,调用possibleStackOverflow(Integer.MAX_VALUE)将抛出StackOverflowException

    您的return子句将返回factorial(VALUE-1)*VALUE的结果。每个factorial(VALUE-1)将被方法调用的结果替换

    这意味着阶乘(4)是:

    (阶乘(1)*(阶乘(2-1)*(阶乘(3-1)*阶乘(4-1)))*4

    这将是


    (1*(2*3))*4即24

    Java使用堆栈在递归调用之间存储信息。有关更多信息,请参阅

    return factorial(value - 1)*value;
    
    返回
    值-1
    乘以
    值的阶乘

    事情是这样的:

    return (factorial(value - 1)) * value;
    
    private static int factorial(int value){
        if (value == 1){
            return 1;
        }
        int a = factorial(value - 1);
        return a * value;
    }
    
    阶乘(4)

    =阶乘(3)*4

    =阶乘(2)*3*4

    =阶乘(1)*2*3*4

    =1*2*3*4=24


    要理解递归,请尝试绘制调用和参数树:

    factorial(4)  = 4 * factorial(4-1)
                                            |
                                    3 * factorial(3-1)
                                                   |
                                           2 * factorial(2-1)
                                                          |
                                                          1
    

    用递归斐波那契公式试试。

    事实上,“return”一词与当前方法不同,并返回一个值/结果。但是,在return“语句”中有一个“表达式”,需要在“return”退出之前对其求值

    例如,返回1+1;需要在操作“+”返回之前对其求值。 调用return func(参数)时;java必须在返回之前调用该函数。在这种情况下,它递归地通过这个“调用堆栈”(函数调用放在一个“堆栈”上,其中最后一个是第一个计算的)

    所以,要真正描述这里发生了什么:

    1) return语句识别表达式

    2) 表达式调用堆栈上的函数

    3) 堆栈上的函数使用另一个要计算的函数命中另一个返回

    4)

    5) 到达“基本情况”,其中找到“1”

    6) 函数调用在sta下执行