Java 有人能解释一下这个程序的控制流程吗?

Java 有人能解释一下这个程序的控制流程吗?,java,Java,这是我AP计算机科学课程中的一个示例程序,我无法理解它的控制流程 public static void mystery( int n ) { System.out.println( "mystery called with n = " + n ); if ( n == 0 ) { System.out.println( "n is zero so no more recursive calls!" ); return; } mystery

这是我AP计算机科学课程中的一个示例程序,我无法理解它的控制流程

public static void mystery( int n )
{
   System.out.println( "mystery called with n = " + n );

   if ( n == 0 )
   {
      System.out.println( "n is zero so no more recursive calls!" );
      return;
   }

   mystery( n - 1 );

   System.out.println( "We did it again with n = " + n );
}

public static void main( String[] args ) 
{
   mystery( 5 );
}
它的输出是:

mystery called with n = 5
mystery called with n = 4
mystery called with n = 3
mystery called with n = 2
mystery called with n = 1
mystery called with n = 0
n is zero so no more recursive calls!
We did it again with n = 1
We did it again with n = 2
We did it again with n = 3
We did it again with n = 4
We did it again with n = 5
到目前为止,我了解递归方法以及它如何通过以下方式调用自身:

mystery( n - 1 );
但是,我不知道它如何在以下情况下输出这五条语句:

n is zero so no more recursive calls!
从逻辑上讲,它似乎只会说:

We did it again with n = 0

有人能帮一个学生解释一下它是如何输出它所做的吗?

在“n”为零之后,这样就没有递归调用了方法继续(状态被放在堆栈上,然后在方法(n-1)调用完成后加载。

当函数完成时,调用它的函数有机会完成并执行更多代码

下面是这个递归是如何发生的一个例子。 每个递归级别都由缩进的增加表示

mystery(5):
    "mystery called with n = 5"
    mystery(4):
        "mystery called with n = 4"
        mystery(3):
            "mystery called with n = 3"
            mystery(2):
                "mystery called with n = 2"
                mystery(1):
                    "mystery called with n = 1"
                    mystery(0):
                        "mystery called with n = 0"
                        "n is zero so no more recursive calls!"
                        mystery(0) returns
                    "We did it again with n = 1"
                    end of mystery(1)
                "We did it again with n = 2"
                end of mystery(2)
            "We did it again with n = 3"
            end of mystery(3)
        "We did it again with n = 4"
        end of mystery(4)
    "We did it again with n = 5"
    end of mystery(5)

下面是一种思考递归程序的好方法:当您阅读程序代码时,即使您还不知道该程序的功能,也要假装您知道该程序的功能。在您的情况下,这种情况如下所示:

  • 如果
    n==0
    ,打印固定消息
    -这就是
    不再递归调用!
    字符串
  • 如果
    n!=0
    ,则打印
    n
    ,然后打印程序为
    n-1
    打印的内容,然后再次打印
    n
    ——换句话说,程序为
    n-1
    打印的内容周围有一个由两条消息组成的“框架”
下面是它的外观:

mystery called with n = <something>
... whatever the program prints in between...
We did it again with n = <something>
n=
…无论程序在两者之间打印什么。。。
我们用n=
第一次打印输出发生在进入调用的递归部分之前;最后一次打印输出发生在从递归部分返回之后。请注意,
在顶部和底部是相同的,因为
n
的值存储在每个堆栈帧上,并在递归展开时设置为上一个值


此图片很容易看到,你一直添加嵌套的“框架”,直到你点击<代码> n== 0 ,此时你在中间打印消息。

神秘方法前五次,<强>该方法不会在递归调用< /强>停止。但我认为,由于神秘是阻塞的,所以只有在返回最后一个递归调用后,才允许该方法结束。因此,在命中n=0时,前五个调用继续执行其原始结论,打印“我们使用n=…”这是该递归方法的运行过程:

mystery(5): {
|   println( "mystery called with n = 5" );
|
|   n != 0:
|       skip return
|
|   mystery(n - 1) is mystery(4)
|
|   call mystery(4): {
|   |   println( "mystery called with n = 4" );
|   |
|   |   n != 0:
|   |       skip return
|   |
|   |   mystery(n - 1) is mystery(3)
|   |
|   |   call mystery(3): {
|   |   |   println( "mystery called with n = 3" );
|   |   |
|   |   |   n != 0:
|   |   |       skip return
|   |   |
|   |   |   mystery(n - 1) is mystery(2);
|   |   |
|   |   |   call mystery(2): {
|   |   |   |   println( "mystery called with n = 2" );
|   |   |   |
|   |   |   |   n != 0:
|   |   |   |       skip return
|   |   |   |
|   |   |   |   mystery(n - 1) is mystery(1);
|   |   |   |
|   |   |   |   call mystery(1): {
|   |   |   |   |   println( "mystery called with n = 1" );
|   |   |   |   |
|   |   |   |   |   n != 0:
|   |   |   |   |       skip return
|   |   |   |   |
|   |   |   |   |   mystery(n - 1) is mystery(0);
|   |   |   |   |
|   |   |   |   |   call mystery(0): {
|   |   |   |   |   |   println( "mystery called with n = 0" );
|   |   |   |   |   |
|   |   |   |   |   |   n == 0:
|   |   |   |   |   |       return from mystery(0)
|   |   |   |   |   }
|   |   |   |   |
|   |   |   |   |   back inside mystery(1), continue executing where we left off
|   |   |   |   |   println("We did it again with n = 1")
|   |   |   |   |   method ends; return to caller
|   |   |   |   }
|   |   |   |
|   |   |   |   back inside mystery(2), continue executing where we left off
|   |   |   |   println("We did it again with n = 2")
|   |   |   |   method ends; return to caller
|   |   |   }
|   |   |
|   |   |   back inside mystery(3), continue executing where we left off
|   |   |   println("We did it again with n = 3")
|   |   |   method ends; return to caller
|   |   }
|   |
|   |   back inside mystery(4), continue executing where we left off
|   |   println("We did it again with n = 4")
|   |   method ends; return to caller
|   }
|
|   back inside mystery(5), continue executing where we left off
|   println("We did it again with n = 5")
|   method ends; program ends
}

例如,将神秘(n-1)替换为神秘(n--);并查看它如何不再执行此操作。当n==0时,它会在打印之前返回,因此当n==0时它不会打印任何内容。以前的操作是递归调用,现在在n==0时完成,因为当n==0时它不会递归调用自己,所以执行将在代码中继续打印。