【问题标题】:Is the return keyword needed for tail recursion?尾递归是否需要 return 关键字?
【发布时间】:2019-03-02 22:06:43
【问题描述】:

我们正在学校学习递归。

根据我在线阅读的内容,您可以通过将递归步骤作为函数执行的最后一件事来优化递归函数。

但是需要 return 关键字吗?即使是 void 函数?

void insert(Node<T>*& n, T value) 
{
    if (n == nullptr)
    {
        n = new Node<T>(value);
        return;
    }
    else if (value < n->get_value())
    {
        Node<T>* left = n->get_left();
        return insert(left, value);
    }
    else
    {
        Node<T>* right = n->get_right();
        return insert(right, value);
    }
}

如果没有 return 关键字,这仍然是尾递归吗?
特别是在else if 中,因为没有它,它将“不再是函数所做的最后一件事”。

【问题讨论】:

标签: c++ recursion


【解决方案1】:

特别是在 else if 中,因为没有它,它将“不再是函数所做的最后一件事”。

这不是真的。

insert 调用是,在所有情况下,除了 n == nullptr 时,该函数所做的最后一件事。

添加多余的return 语句并不会改变这一点。

这个:

void bar() {}

void foo()
{
    return bar();
}

相当于这个:

void bar() {}

void foo()
{
   bar();
   return;
}

或者这个:

void bar() {}

void foo()
{
   bar();
}

在所有方面。

事实上,我们允许在返回void的函数中这样做的唯一原因(请记住,您实际上并没有在这里返回任何值!),是使实现模板更容易一些。

而且,在所有这些示例中,编译器不需要为调用bar() 设置新的堆栈帧。在递归函数的情况下,这会给你尾递归

【讨论】:

  • 所以即使在if else?
  • 因为我明白你所说的返回,但你的例子只显示在函数的末尾。不在if 内,后面有更多代码
  • @user644361 没有“更多代码”。在程序的每条可能路径上,对insert 的递归调用是最后发生的事情。编译器应该能够知道它需要做的就是选择适当的参数。但是您可以查看程序集以了解编译器的作用。不管怎样,这与return无关。
【解决方案2】:

这些返回在您的代码中没有任何作用。

只需删除一个“return;”完全排成一行。

去掉其他两行的返回。

我不是尾递归方面的专家,但我知道你的代码做同样的事情,而且没有返回就更简单了。

【讨论】:

  • ifelse if 块中的 return 阻止程序继续运行
  • @user644361 — 返回不会停止程序;他们阻止 function 做更多的事情。但是这个特定的函数无论如何都没有做更多的事情,所以返回在这里真的没有做任何事情。 (假设if 之后的两行我们应该在花括号内)
  • @user644361 如果任何 if、else-if 或 else 子句中有其他行,则返回可能具有某些值。实际上,执行将恰好进入这些子句之一,然后在从递归返回后,落到函数的底部。无需返回即可更改执行路径。
  • @PeteBecker 不错的收获!我错过了。
  • @PeteBecker 是的,我的意思是函数...else if 块中的 return 关键字可能正在使函数尾递归。这就是我要问的
【解决方案3】:

在您的代码中,所有三个 returns 什么都不做,可以删除。

如果函数返回void,则return 仅用于 提前终止该函数。在你的代码中,毕竟那些returns 什么都没有,所以它们是多余的。


另一方面,如果一个函数返回非void,那么它必须通过return(或异常或std::exit等)终止。如果控制到达此类函数的关闭},则行为未定义。

main() 是此规则的一个例外,到达main() 的结束} 会自动执行return 0;


另外,正如@RetiredNinja 所说,“n 需要是对指针的引用”。否则您对n 所做的更改将被丢弃,并且通过new 分配的内存被泄露。

【讨论】:

    猜你喜欢
    • 2012-12-06
    • 2021-10-20
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 2018-07-13
    • 2021-12-17
    相关资源
    最近更新 更多