2010-01-11 82 views
3

我对下面的代码问题的Java return语句

private void printTree(Node node){ 
    if(node==null) return; 
    printTree(node.left); 
    System.out.print(node.data+" "); 
    printTree(node.right); 
} 

我真的不明白的点“回报;”在那里陈述。它看起来像节点为空,代码不返回任何内容。但是如果没有这一行,编译器会产生一个异常错误。

回答

16

这是一个递归函数(反复调用自己的函数)。 return的目的是为了确保它不会永远这样做,因为您在树的底部运行时会导致空指针异常。

会发生什么情况是,您第一次用一个节点(通常,但并非总是根节点)调用此函数时,它将首先打印该节点的左子树,然后节点本身,然后是该节点的右侧子树。

打印出子树的方式是使用该子树的顶层节点调用自身。这是优雅地处理递归结构的一种非常普通的方法。

null的测试是这样的,它有一个条件,当它到达一个没有孩子在你正在检查的特定面(左边或右边)的节点时,停止搜索树的层级。

举例来说,假设你有下面的树(大写字母与他们的数字与数字真正的节点是它们的价值,并===标记为空值):

   A26    Level 0 
       | 
     +------+------+ 
     |    | 
     B14   C84   Level 1 
     |    | 
    +--+--+  +--+--+ 
    |  |  |  | 
    D11 ===  === E99  Level 2 
    |     | 
+--+--+    +--+--+ 
|  |    |  | 
=== ===   === === Level 3 

这里会发生什么,当你用A调用函数。

You call the function (level 0) with A. 
    The function will call itself (level 1) with B (A left). 
    The function will call itself (level 2) with D (B left). 
     The function will call itself (level 3) with null (D left). 
     The function will return to level 2. 
     The function will print out 11 from D. 
     The function will call itself (level 3) with null (D right). 
     The function will return to level 2. 
     The function will return to level 1. 
    The function will print out 14 from B. 
    The function will call itself (level 2) with null (B right). 
     The function will return to level 1. 
    The function will return to level 0. 
    The function will print out 26 from A. 
    The function will call itself (level 1) with C (A right). 
    The function will call itself (level 2) with null (C left). 
     The function will return to level 1. 
    The function will print out 84 from C. 
    The function will call itself (level 2) with E (C right). 
     The function will call itself (level 3) with null (E left). 
     The function will return to level 2. 
     The function will print out 99 from E. 
     The function will call itself (level 3) with null (E right). 
     The function will return to level 2. 
     The function will return to level 1. 
    The function will return to level 0. 
    The function will return to you. 

其结果是,它打印出的序列DBACE,其在排序的树中,是按排序顺序(11, 14, 26, 84, 99)的元素。


或者一个简单的版本,如果你不能打扰通过我上面大量的解释为:

   A26    Level 0 
       | 
     +------+------+ 
     |    | 
     B14   ===   Level 1 
     | 
    +--+--+ 
    |  | 
    === ===     Level 2 

You call the function (level 0) with A. 
    The function will call itself (level 1) with B (A left). 
    The function will call itself (level 2) with null (B left). 
     The function will return to level 1. 
    The function will print out 14 from B. 
    The function will call itself (level 2) with null (B right). 
     The function will return to level 1. 
    The function will return to level 0. 
    The function will print out 26 from A. 
    The function will call itself (level 1) with null (A right). 
    The function will return to level 0. 
    The function will return to you. 

在这种情况下,你会得到BA(14,26)

+2

或者在下一行生成空指针异常。 – Don 2010-01-11 05:03:59

+0

好点,@Don,你几乎肯定会在堆栈溢出之前得到一个空指针异常(除非你的堆栈特别小)。修改来修复。 – paxdiablo 2010-01-11 05:54:11

+0

对于一个全面的,很好解释的答案+1。 – Matt 2010-01-11 10:27:14

4

声明为void的任何方法都不会返回值。它不需要包含返回语句,但它可能会这样做。在这样的情况下,返回语句可用于分支出来的控制流程块的和退出的方法和简单地使用这样的:

return; 

从Java LangSpec:

14.17返回声明

返回语句返回控制到 方法(§8.4,§15.12) 或构造函数(§8.8,§15.9)的调用者。

ReturnStatement: 
     return Expressionopt ; 

没有表达 return语句必须包含在该被宣布为 方法的主体,采用 关键字void,不返回 (8.4节),或者在身体的任何值一个 构造函数(§8.8)。如果返回语句 出现在实例初始化程序 或静态初始化程序(第8.7节)中,则会发生编译时 错误。 A 返回语句不带表达式 尝试将控制权转移给该方法的调用者或包含它的构造函数 。确切地说,没有表达式 的 返回语句总是突然完成,原因 是没有值的返回。

与表达 的return语句必须在一个方法包含在该被声明为返回 (8.4节)或编译时错误 发生值 声明。表达式必须表示某种类型T的变量或值,或发生编译时错误。 T 类型必须是可分配的(第5.2节) 声明的结果类型的方法,或者 发生编译时错误。

0

在我看来,如果你的节点是null,它会在抛出NullReferenceException之前离开函数调用。因为它是递归的,所以它需要通过向其父节点“退出”来处理树的节点(树叶)。

+0

是编译器是否给出错误,或者你是否在运行时得到错误? – 2010-01-11 05:03:01

+0

当然,在运行时。 – 2010-01-11 05:03:49

0

你也有回报,所以你不要调用node.data。请记住,如果它为null,则无法在其上调用实例方法。

0

'return'语句在这里作为递归调用的终止条件。每个递归方法都需要一个临时终止条件,否则它会进入无限循环。

if(node==null) return; 

此声明基本上表示您已到达叶节点(分支的最后一个节点)并终止光标的任何进一步移动。

,你得到的回报除去例外情况是由于这样的事实,你没有任何进一步的节点移动到一旦你已经达到了叶节点和声明printTree(node.left); & printTree(node.right);无效。

0

一个不太令人困惑的方式来写,这将是:

private void printTree(Node node){ 
    if (node.left != null) { 
     printTree(node.left); 
    } 
    System.out.print(node.data); 
    if (node.right != null) { 
     System.out.print(" "); 
     printTree(node.right); 
    } 
} 
+3

对我来说,问题中提出的版本看起来更清晰,因为递归终止条件显而易见。 – sateesh 2010-01-11 05:49:32

+1

这取决于你的编码风格。拥有多于一个的回报通常会导致阅读困难。不是每个人都会同意。 – fastcodejava 2010-01-11 06:36:18

+1

这两个似乎都是顺序遍历二叉树的明确实现:http://en.wikipedia.org/wiki/Tree_traversal – trashgod 2010-01-11 06:39:45

0

它有时很难辨认回报,这不是结尾。大多数人习惯于在这里找到它。此外,没有任何回报的回报也可能令人困惑。一个更明显的写法是:

 
private void printTree(Node node) { 
    if(node!=null) { 
     printTree(node.left); 
     System.out.print(node.data+" "); 
     printTree(node.right); 
    } 
} 

所以,简单地说,“如果有节点,请访问它”!

0

返回语句是简单的在下面的方式来理解:

方法没有返回类型不能返回值,但返回的控制。

任何可以返回值的方法都可以返回必须与返回方法类型兼容的值。