【问题标题】:Are tail-recursive functions ALWAYS to be avoided?是否总是要避免尾递归函数?
【发布时间】:2010-07-20 11:30:16
【问题描述】:

如果我没记错的话,尾递归函数总是有一个简单的非递归等效函数。 由于递归涉及不必要的函数调用开销,因此最好采用非递归方式。

这个假设总是正确的吗?还有其他支持/反对尾递归的论据吗?

【问题讨论】:

    标签: performance recursion tail-recursion


    【解决方案1】:

    如果您使用的是具有良好编译器的语言,那么这些类型的递归可以被优化掉,所以在这些情况下,如果使用递归可以提高可读性,我会说坚持下去。

    【讨论】:

    • 听起来不错,但现在欢迎来到现实世界。您编写递归函数而不是迭代函数。编译器不会将其转换为迭代的。它一直有效,直到您遇到足够长的输入。你的同事过来解释你的错误。你重写它。
    • 这真的取决于你对环境的了解以及函数在迭代形式中的邪恶/邪恶程度。当然要务实。我认为尾递归函数并非总是要避免的。
    • 谢谢,fd。您和其他回答者已经解释了为什么有时使用尾递归是有意义的。
    • 如果需要软件正确性和更容易的验证,那么避免递归实现,因为证明终止变得更加困难。相关阅读Safety Critical Software
    【解决方案2】:

    不,这并不总是正确的。许多语言和/或编译器可以轻松优化尾递归调用,并将其重写为迭代版本,或者以某种方式将堆栈帧重用于后续调用。

    Scheme 语言要求实现使用tail call optimization

    gcc 也可以优化尾调用,考虑一个释放链表中所有节点的函数:

    void free_all(struct node *n)
    {
        if(n != NULL) {
            struct node *next = n->next;
            free(n);
            free_all(next);
        }
    }
    

    编译为,优化:

    free_all:
            pushl   %ebp
            movl    %esp, %ebp
            pushl   %ebx
            subl    $20, %esp
            movl    8(%ebp), %eax
            testl   %eax, %eax
            je      .L4
            .p2align 4,,7
            .p2align 3
    .L5:
            movl    4(%eax), %ebx
            movl    %eax, (%esp)
            call    free
            testl   %ebx, %ebx
            movl    %ebx, %eax
            jne     .L5
    .L4:
            addl    $20, %esp
            popl    %ebx
            popl    %ebp
            ret
    

    即简单跳转,而不是递归调用free_all

    【讨论】:

      【解决方案3】:

      没有。

      追求可读性。许多计算可以更好地表示为递归(尾或其他)函数。避免它们的唯一其他原因是,如果您的编译器没有进行尾调用优化,并且您预计您可能会破坏调用堆栈。

      【讨论】:

        【解决方案4】:

        这取决于语言,但通常开销并不大。它可能是主观的,但递归函数往往更容易理解。大多数情况下,您不会注意到性能差异。

        除非我的平台非常不擅长处理尾递归(即根本不这样做,但总是压入堆栈),否则我会选择尾递归。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-25
          • 2015-12-10
          • 1970-01-01
          • 1970-01-01
          • 2012-12-06
          • 2012-01-06
          相关资源
          最近更新 更多