对于每个递归算法,都可以创建等效的非递归版本?

时间:2011-01-23 20:49:50

标签: recursion

递归很有趣。但是,在安全关键应用程序中,它被视为危险的东西(因为我认为堆栈溢出?)。

想象一下,你需要处理一个你喜欢的语言的子集,这不会允许递归 - 这对你来说是一场灾难吗?

正式问题:对于每个递归函数,都可以创建一个完全等效的非递归函数 - 这是真的吗?是关于它的定理?

4 个答案:

答案 0 :(得分:3)

是的,每个这样的函数都可以重写为非递归函数。我不确定是否有正式的方法,但它在文献中被称为“递归展开”或“递归展开”。

在大多数情况下,应避免递归。特别是在上述类型的系统中,MISRA-C禁止递归。

有一些罕见的情况,递归很方便,使代码更有效,一些二叉树实现等。

但递归的主要目的是教它让学生感到困惑,这样当他们成为有经验的人时,他们可以把它教给困惑的学生,这样...... :)

答案 1 :(得分:1)

这样想:你的程序是由一组有限的CPU执行的(让我们假设你现在有1个),执行一系列指令。 CPU如何处理递归?它无法创建自己的新实例来解决稍微简单的问题,因此它使用堆栈来跟踪它的位置。因此,对于任何可以在任何编程语言中递归表达的算法,您也可以使用堆栈以与CPU相同的方式手动“展开”递归。 (请注意,对于许多算法,特别是只有一次递归调用的算法,通常有更简单的方法来删除递归,例如简单的迭代。)

答案 2 :(得分:0)

通常使用递归,因为没有简单的方法可以知道你需要迭代多少次问题。

使用简单循环替换递归函数可能需要大量额外工作,但如果您觉得有必要,通常应该可以这样做。

如果您的递归函数具有适当的基本情况,那么堆栈溢出的危险性很小。

答案 3 :(得分:0)

递归不是免费的

需要相当大的内存空间(通常在堆栈上)
和CPU时间(通过使用调用,重建堆栈帧等) 在紧密循环中,这使得递归算法比其非递归等价物慢。

如果速度和堆栈限制不是问题,请务必留下递归,但如果在紧密循环中使用递归,(通常是这种情况)
通过逐步递归递归,您可以获得许多优化选项。

因为:也许:
 1.您无需保存所有这些寄存器/变量  2.您不必跳回到您来自的完全相同的地方  3.您不需要为每次递归调用该清理代码  你可以展开一些循环
 5.您可以对该非递归例程使用inline指令。

我对递归的平均问题是它最常用的数据结构:

树需要指针和指针需要随机内存访问(它们遍布整个地方)这对缓存使用不利,因为顺序访问比随机访问快得多。
如果用二维数组替换二叉树,则会浪费50%的空间,(除非您将另一棵树倒置在数组中),但是您获得了许多叶子的顺序访问选项而且您不必使用指针,节省空间。

Example of a binary tree stored in an array
+-----------------+
|0eeeeeeeeeeeeeeee| //no pointers needed, parent/child, is y dimension,
|11       dddddddd| //sibbling is x dimension of the array.
|2222         cccc|  //The 123 tree is stored root up.
|33333333       bb|  //Notice how the abc-tree is stored upside down 
|4444444444444444a|  //The wasted space in the middle, is offset by the fact 
+-----------------+  //that you do not need up, down, and sibbling pointers.
相关问题