我喜欢递归。我认为它可以简化很多东西。也许有人不同意;但我认为它还使得代码更易于阅读。然而,我注意到在像C#这样的语言中递归并没有像在LISP中那样经常使用(顺便说一下,LISP是我的最爱,因为它支持递归)。
是否有人知道是否有任何好理由不在像C#这样的语言中使用递归呢? 是否比迭代更昂贵?
我喜欢递归。我认为它可以简化很多东西。也许有人不同意;但我认为它还使得代码更易于阅读。然而,我注意到在像C#这样的语言中递归并没有像在LISP中那样经常使用(顺便说一下,LISP是我的最爱,因为它支持递归)。
是否有人知道是否有任何好理由不在像C#这样的语言中使用递归呢? 是否比迭代更昂贵?
它们比迭代更昂贵吗?
是的,它们比迭代更昂贵。许多Lisp变体支持尾调用优化的概念,它允许将许多递归函数调用转换为迭代函数调用(这有点简化了)。如果不支持尾调用,则递归函数调用会在堆栈上使用越来越多的内存。
它们比迭代更昂贵吗?
是的。递归需要创建一个新的堆栈帧以及一个调用和返回,而迭代通常只需要一个比较和分支,使其速度明显更快。但是,编译器可以对某些递归调用(即尾递归)执行尾调用优化,从而使它们重用堆栈帧,大大降低了递归调用的成本,有效地将其转换为迭代。Scheme 实际上要求 Scheme 编译器实现尾调用优化。
像Lisp和F#这样的函数式编程语言可以将许多尾递归函数作为循环内部实现,从而能够避免函数调用时的堆栈开销。C#不支持尾递归,但是F#支持。
如果一个算法最自然的表达形式是递归形式,并且如果堆栈深度很小(在log(N)范围内,即通常<20),那么请务必使用递归。(任何由于迭代而导致的性能增益将是一个小常数因子)。
如果有任何危险,使得堆栈增长得过大,并且你的语言/编译器/运行时系统不能保证尾调用优化,则应避免使用递归算法。
有没有人知道在像C#这样的语言中不使用递归的好理由?它比迭代更昂贵吗?
是的,因为C#不支持尾递归。当使用递归对大型集合进行简单迭代时,如果递归过深,很容易出现StackOverflowException并使应用程序崩溃。
Scheme是我所知道的唯一需要尾调用优化的Lisp方言,而且它们往往会大量使用递归。在其他不需要这个特性的Lisp方言中(比如Common Lisp),我并没有看到递归被使用得比其他语言更多。