有人可以解释这个程序的控制流程吗?

时间:2016-02-06 20:46:56

标签: 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( 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

任何人都可以帮助学生并向我解释它是如何输出的吗?

5 个答案:

答案 0 :(得分:4)

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

以下是此递归如何发生的说明。 每个递归级别由缩进的增加表示。

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)

答案 1 :(得分:2)

'n为零之后不再有递归调用!'方法继续(状态被放在堆栈上,然后在方法(n-1)的调用结束后加载。

答案 2 :(得分:1)

这是一种考虑递归程序的好方法:当你阅读程序的代码时,假装你知道程序的功能,即使你还不知道它。在您的情况下,这将是这样的:

  • 如果n == 0,则打印固定消息 - 这是no more recursive calls!字符串
  • 如果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>

在进入呼叫的递归部分之前,第一次打印输出; 从递归部分返回后,发生了最后一次打印输出。请注意,<something>在顶部和底部是相同的,因为n的值存储在每个堆栈帧上,并在递归展开时设置为先前的值。

有了这张图片,很容易看到你继续添加嵌套的“框架”,直到你点击n==0,此时你在中间打印信息。

答案 3 :(得分:0)

通过神秘方法的前五次,该方法不会停止在递归调用。它继续,输出“我们再次做到了”。但我想,因为神秘是阻塞,所以只有在返回最后一次递归调用后才允许该方法完成。因此,当打到n = 0时,前五个调用继续到他们原来的结论,打印“我们再次使用n = ...”

答案 4 :(得分:0)

以下是这个递归方法的用法:

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
}