2013-04-11 75 views
4

有人可以向我解释为什么打印出来1 2 3 4 5?我想它会打印出4 3 2 1 0,但我的书和日食都说我错了。Java - 理解递归

public class whatever { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     xMethod(5); 

    } 

    public static void xMethod(int n){ 
     if (n>0){ 
      xMethod(n-1); 
      System.out.print(n + " "); 
     } 
    } 


} 
+0

的递归函数和它们的堆栈帧运行时评估。 – squiguy 2013-04-11 06:11:41

回答

18

这是很简单,这些都是

main 
    xMethod(5) 
     xMethod(4) 
      xMethod(3) 
      xMethod(2) 
       xMethod(1) 
        xMethod(0) 
       print 1 
      print 2 
      print 3 
     print 4 
    print 5 

所以你看到的来电印刷品是1,2,3,4,5

+0

这正是我所需要的,但是你也可以解释为什么打印语句甚至被调用。它看起来应该永远不会被调用。 @ilomambo – BluceRee 2013-04-11 06:15:50

+4

@BluceRee:为什么不呢?最终,每个函数都会返回。 (好吧,有一些不这样做,但这是技术上的问题。)当最内层的xMethod调用返回时,下一个最内层的调用将立即从其停止的地方开始:在调用之后本身,在'印刷'。 – cHao 2013-04-11 06:17:31

+0

@ilomambo我认为,当if语句变成false而退出循环时。 – BluceRee 2013-04-11 06:19:16

-2

这是正确的代码

System.out.print(n + " "); 
xMethod(n-1); 
+1

我知道,有什么不对的代码。我只是想知道为什么它做它做什么。 – BluceRee 2013-04-11 06:12:39

+0

不,没有什么特别的错误代码。 – Makoto 2013-04-11 06:19:58

3

它首先调用自身递归只有当递归调用结束它打印。 所以,想想它称之为第一完成 - 这是当n = 0 则n = 1等

这是一个堆栈,从堆栈中取(递归调用后)后打印,这样的顺序颠倒。 如果在放入堆叠前打印,则订单将被保留。

+0

因此堆栈通过打印语句清空? – BluceRee 2013-04-11 06:17:03

2
System.out.print(n + " "); 
xMethod(n-1); 

它将打印5 4 3 2 1.因为它会首先打印,然后调用xMethod。

对你来说

xMethod(n-1); 
System.out.print(n + " "); 

这将达到终止条件,那么POP操作并打印。所以1 2 3 4 5

-1

此 xMethod第(n-1); System.out.print(n +“”);

应该是:

 System.out.print(n + " "); 
     xMethod(n-1); 
+1

为什么*应该是那个? – Makoto 2013-04-11 06:17:37

+0

调用正在进行。所以在你调用'System.out.print(n +“”)之前,你对从n - 1到0的每个值调用xMethod()。当它变得小于零时,它将不会再调用xMethod并进入下一步,在这种情况下是打印方法。然后它将继续返回到调用者进程并执行下一步,再次执行打印方法。依此类推,直到它返回到调用堆栈的顶部并执行最后一个打印语句并且程序结束。 – 2013-04-11 06:25:28

+0

是的......这就是它的工作原理*。这不是为什么代码应该颠倒的理由。 – Makoto 2013-04-11 06:26:31

1

xMethod被称为直到n0。该堆栈将是xMethod(5)->xMethod(4)->xMethod(3)->xMethod(2)->xMethod(1)->xMethod(0)。当它完成xMethod(0)时,它将弹出到xMethod(1)的下一行,打印1。然后重复此操作,直至退出xMethod(5)

如果你去和扩大各xMethod因为它是所谓的代码看起来是这样的:

{ 
    nA = 5 // What n was set at first 
    if (nA>0){ 
     { 
      // Instead of xMethod(n-1), 
      // we're setting nB to nA - 1 and 
      // running through it again. 
      nB = nA - 1 // nB is 4 

      if (nB>0){ 
       { 
        nC = nB - 1 // nC is 3 
        if (nC>0){ 
         { 
          nD = nC - 1 // nD is 2 
          if (nD>0){ 
           { 
            nE = nD - 1 // nE is 1 
            if (nE>0){ 
             { 
              nF = nE - 1 // nF is 0. 
              if (nF>0){ 
               // This will never execute b/c nF is 0. 
              } 
             } 
             System.out.print(nE + " "); // prints 1 
            } 
           } 
           System.out.print(nD + " "); // prints 2 
          } 
         } 
         System.out.print(nC + " "); // prints 3 
        } 
       } 
       System.out.print(nB + " "); //prints 4 
      } 
     } 
     System.out.print(nA + " "); //prints 5 
    } 
} 
+2

你是对的......在10,000英尺。你能否提供更多细节? – Makoto 2013-04-11 06:20:44

0
1 public static void xMethod(int n){ 
    2 if (n>0){ //the base condition 
    3   xMethod(n-1); //function is again called with one value less than previous 
    4   System.out.print(n + " "); //now print 
    5  } 
    6 } 

现在看线#3,由于没有打印b再次调用该功能,因此从#3行开始,呼叫再次到达#1行。这意味着n是5,但是新的呼叫需要n = 4,并且它继续前进,直到线2指示n现在小于0.

当条件#2失败时,它到达第# 5,然后是第6行,这意味着函数已经结束执行,此时n = 1。

现在应该在哪里返回呼叫?在最后一个函数被调用的第#3行,它将从执行第4行的堆栈弹出,该行打印n的值,即1 2 3 4 5.

4

这是调用堆栈的结果。以下是n = 5致电后的样子。由于此调用链的底部实际上是堆栈的顶部,所以将您的头旋转180度。

  • xMethod(5)
    • xMethod(4)
      • xMethod(3)
        • xMethod(2)
          • xMethod(1)
            • xMethod(0)

在递归调用,你有两个案例 - 基本情况和递归情况。这里的基本情况是n == 0,并且不会发生进一步的递归。

现在,当我们开始从这些调用回来时会发生什么?也就是发生了什么后的递归步骤?我们开始做System.out.print()。由于存在防止递归n == 0打印时的情况,所以我们既不递归也不打印。

所以,你得到1 2 3 4 5作为输出的原因是由于电话正在从堆栈中弹出的方式。

+0

真棒解释。 – kobe 2017-09-08 19:20:26

2

为了解释递归是如何工作的,让我们来看看阶乘计算的样本:

int factorial(int i) { 
    if (i == 0) { 
     return 1; 
    } 
    return i * factorial(i - 1); 
} 

例如,让我们的5因素值:

int result = factorial(5); 

记住退出值:

if (i == 0) { 
    return 1; 
} 

并返回值:

i * factorial(i - 1) 

只要看看迭代(根据返回值):

5*factorial(4) -> 4*factorial(3) -> 3*factorial(2) -> 2*factorial(1) -> 1*factorial(0) 

事实上,它是:

5*(4*(3*(2*(1*factorial(0))))) 

原因factorial(4) == 4*factorial(3), factorial(3) == 3*factorial(2)

最后一次迭代是factorial(0),等于1(查看退出值)。

在结果:

5*(4*(3*(2*(1*1)))) = 120