如果我没记错的话,尾递归函数总是有一个简单的非递归等价。 由于递归涉及不必要的函数调用开销,因此最好以非递归方式进行。
这种假设总是如此吗?对于尾递归是否还有其他参数?
答案 0 :(得分:6)
如果您正在使用具有良好编译器的语言,那么可以优化这些类型的递归,因此在这些情况下如果它提高了使用递归的可读性,我会坚持使用它。
答案 1 :(得分:6)
不,并非总是如此。许多语言和/或编译器可以轻松地优化尾递归调用,并将其重写为迭代版本,或者以某种方式重用堆栈帧以用于后续调用。
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
答案 2 :(得分:2)
没有
寻求可读性。许多计算更好地表示为递归(尾部或其他)函数。避免它们的另一个原因是,如果你的编译器没有进行尾调用优化,并且你希望你可能会破坏调用堆栈。
答案 3 :(得分:1)
这取决于语言,但通常开销并不大。它可能是主观的,但递归函数往往更容易理解。大多数时候你都不会注意到性能差异。
除非我的平台在处理它时非常糟糕(即根本不做,但总是推到堆栈上),我会去尾递归。