【问题标题】:java return statementjava返回语句
【发布时间】:2011-01-03 15:26:12
【问题描述】:

我对以下代码有疑问

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

我真的不明白“回归”的意义;那里的声明。看起来如果节点为空,代码什么也不返回。但如果没有该行,编译器会生成异常错误。

【问题讨论】:

    标签: java data-structures binary-tree return


    【解决方案1】:

    这是一个递归函数(一个反复调用自身的函数)。 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)

    【讨论】:

    • 好点,@Don,你几乎肯定会在堆栈溢出之前得到一个空指针异常(除非你的堆栈特别小)。修改为修复。
    【解决方案2】:

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

    return;
    

    来自 Java 语言规范:

    14.17 返回声明

    return 语句将控制权返回给 方法的调用者(§8.4,§15.12) 或构造函数(第 8.8 节、第 15.9 节)。

    ReturnStatement:
            return Expressionopt ;
    

    没有表达式的返回语句 必须包含在 声明的方法,使用 关键字void,不返回任何值 (§8.4),或在 构造函数(第 8.8 节)。编译时 如果返回语句发生错误 出现在实例初始化程序中 或静态初始化程序(第 8.7 节)。一种 没有表达式的返回语句 试图将控制权转移给 方法或构造函数的调用者 包含它。准确地说,一个 没有表达式的返回语句 总是突然完成,原因 是没有价值的回报。

    带有表达式的返回语句 必须包含在方法中 声明返回的声明 值(第 8.4 节)或编译时错误 发生。表达式必须表示 某种类型 T 的变量或值,或 发生编译时错误。 T型 必须可分配(§5.2)给 方法的声明结果类型,或 发生编译时错误。

    【讨论】:

      【解决方案3】:

      在我看来,如果您的节点为空,它将在抛出 NullReferenceException 之前退出函数调用。因为它是递归的,所以它需要它通过“回退”到其父节点来处理树的节点(叶子)。

      【讨论】:

      • 是编译器给出了错误,还是您在运行时收到了错误?
      【解决方案4】:

      你也有回报,这样你就不用调用 node.data。请记住,如果它为 null,则不能对其调用实例方法。

      【讨论】:

        【解决方案5】:

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

        if(node==null) return;
        

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

        您在删除 return 时遇到的例外是由于一旦到达叶节点就没有任何其他节点可以移动,并且语句 printTree(node.left);printTree(node.right); 无效。

        【讨论】:

          【解决方案6】:

          一种不那么令人困惑的写法是:

          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);
              }
          }
          

          【讨论】:

          • 对我来说,问题中提出的版本看起来更清晰,因为递归终止条件很明显。
          • 这取决于你的编码风格。拥有多个回报通常会使阅读变得更加困难。可能不是每个人都会同意。
          • 两者似乎都是二叉树中序遍历的清晰实现:en.wikipedia.org/wiki/Tree_traversal
          • 这不是同一个代码:您仍然可以获得NullPointerException(有时需要!)
          • 是的,在调用这个方法之前需要做空检查。
          【解决方案7】:

          有时很难识别出没有结束的回报。大多数人习惯于在这里找到它。此外,不返回任何内容的 return 也可能令人困惑。更明显的写法是:

          私人无效打印树(节点节点){ 如果(节点!=空){ 打印树(节点。左); System.out.print(node.data+" "); printTree(node.right); } }

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

          【讨论】:

            【解决方案8】:

            return 语句可以通过以下方式简单理解:

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

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

            【讨论】:

              猜你喜欢
              • 2012-06-07
              • 2015-05-03
              • 2017-01-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-11-01
              • 2015-08-23
              相关资源
              最近更新 更多