2017-04-06 36 views
1

我很久以前在类中写了一个基本的递归问题,我试图记住我如何获得打印的输出。Java递归输出名称向前和向后

它基本上打印出一个名称向前和向后。我了解它如何向前打印名称,但我对于如何向后打印名称无能为力。我做了一个调试,以逐步查看发生了什么,但无法理解名称向前打印后index如何减少。

public class CharRecursion 
{ 

public static void printName(String name, int index) 
    { 
    if(index > name.length() - 1) 
    { 
     return; 
    } 
    else 
    { 
     System.out.println(name.charAt(index)); 
     printName(name, index + 1); 
     System.out.println(name.charAt(index)); 
    } 
    } 
public static void main(String[] args) 
    { 
     printName("Brian", 0); 
    } 

} 

输出是BriannairB

+0

看看第二个'System.out.println' - 它在递归达到结束后被调用。 –

+0

除了Jaroslaw的评论,请注意'index + 1'不会改变'index'的值。因此,在下一行中,打印相同的字符。 –

+0

谢谢。我明白第二个System.out.println是什么导致它,但它是如何索引正在减少导致字母倒退?我必须错过简单的东西。 –

回答

2

向后部分来自第二System.out.println(name.charAt(index));声明。

这一个只调用一次递归调用已经结束,递归,所以你最终与反向字符串,看看后缀标志:

System.out.println(name.charAt(index) + " - "); 
    printName(name, index + 1); 
    System.out.println(name.charAt(index) + " * "); 

你得到:

B - 
r - 
i - 
a - 
n - 
n * 
a * 
i * 
r * 
B * 

由于实际的调用顺序为:

printName(name,0)> printName(name,1)> printName(name,2)> printName(name,3)> printName(name,4)

第一个电话解决您的第二println说明会printName(name, 4),然后printName(name, 3)等..和印刷的顺序变为:

System.out.println(name.charAt(4) + " * "); 
System.out.println(name.charAt(3) + " * "); 
System.out.println(name.charAt(2) + " * "); 
System.out.println(name.charAt(1) + " * "); 
System.out.println(name.charAt(0) + " * "); 
1

明白这一点的方式是通过其手动步骤,使用笔和纸。 我不能强烈推荐你实际上对这件事物理上用真正的纸片,直到你明白发生了什么。

用一张纸记录输出。

每次调用printName()时都使用一张新的单独纸张。

main()开始。当您看到printName("Brian", 0)时,这是启动新纸张的信号。在工作表顶部,写入输入:name - "Brian", index = 0

现在你在printName(),所以一步一步地通过它。 0小于"Brian".length() - 1,这样你就可以跳到else块:

  • System.out.println(name.charAt(index)); - 这么写的"Brian".charAt(0)结果在你的输出表:B

  • printName(name, index + 1) -- since you're seeing printName()again, take another sheet of paper, write the inputs名称= “布赖恩”,索引= 1`在顶部,和地方此上与前一薄片的顶部。

继续以这种方式工作,您将继续添加到您的纸张堆。这与Java维护的执行堆栈直接类似;这是您在堆栈跟踪中看到的相同堆栈。

最终你会达到index = "Brian".length() -1的点,所以你回来。当您看到return时,请取下正在使用的纸张,将其拧紧并将其投入垃圾箱。运行时已完成此方法的调用。继续下面的表格,从中断。你现在在第二个System.out.println(name.charAt(index));。所以把这个字符写在输出表上。

当你完成后,你会发现你在输出表上写了“BriannairB”,你应该对递归有更好的理解。

每张纸都代表堆栈帧。请记住:

  • 在执行期间的给定时刻,只有最上面的堆栈帧在执行过程中“可见”。
  • 局部变量和参数存储在堆栈帧中。在执行的某个时刻,当前堆栈帧中index的值将为3。这对下面堆栈帧中index的值没有影响 - 这是一个完全独立的存储器,当3帧结束并弹出堆栈时仍将为2

一旦你得到的这个窍门,但是,你可以看看它在更多的“声明”的水平。​​是做什么的?

它打印“B”,然后printName("Brian", 1),然后“B”。

我觉得这个实现稍微容易理解:

void printName(String s) { 
     if(s.length() > 0) { 
      System.out.println(s.charAt(0)); 
      printName(s.substring(1)); 
      System.out.println(s.charAt(0)); 
     } 
    } 

所以,printName("Brian")写道B然后printName("rian")然后B

或者从最深去堆栈会:

printName("")没有写。

因此printName("n")写入n然后printName("")然后n - 这是nn

+0

好!一旦你提到堆栈跟踪,它开始点击。所以基本上第二个println语句会通过堆栈返回,然后吐出接下来出现的任何内容,最终反向。如果我理解正确。 –

+0

@BrianHogans我认为你的程序执行过程的心理模型有点偏离。 'println'语句不会“穿过”任何东西。 JVM按声明逐个执行方法。当它遇到一个方法调用时,它将添加到堆栈中,并在处理该方法调用时将其他所有内容都保留。当它到达方法调用的结尾时,它将从堆栈中移除该项目并继续执行。如果你遵循我的建议并在纸上“运行”,那么你就是JVM。 – slim

+0

好的,我一定会那样做的。我想确保在我转向不同的东西之前,我在概念上得到这一点。 –

0

以下是程序的执行顺序。程序以递归方式调用printName("Brian",index)函数,其在每次调用之前首先执行System.out.println(name.charAt(index));。当索引达到5函数调用开始返回时,第二个System.out.println(name.charAt(index));在每次返回后执行。