应该避免在C / C ++中使用递归调用吗?

应该避免在C / C ++中使用函数的递归调用吗?

我从事机器学习/数据挖掘工作,因此让我的代码可扩展至关重要。

当我使用Java时,我尽可能避免使用递归调用,因为我经常让我的调用堆栈溢出。 虽然有控制分配给调用堆栈的内存量的选项,但我认为让我的程序依赖于较少数量的参数是更理想的。 因此,当很清楚如何在没有递归调用的情况下实现,可能使用自己管理的堆栈,我这样做了。 但即使在Java中,我也不确定这是一门正确的学科。

据我所知,C / C ++中没有调用堆栈,所以我不担心溢出它。 因此,我很好奇:在程序的可伸缩性方面,是否会尝试避免使用递归,或者是否鼓励它,或者它是特定于问题的?

C&C ++中的调用堆栈在某种程度上类似于C ++ 的vtable – 据我所知,它没有在标准中提及,即,实现不是强制实施的,但是出于所有实际目的,它几乎总是实现的办法。

当然,有一些深奥的架构,特别是在嵌入式世界中,可能会避开堆栈。 PIC是堆栈不友好架构的一个例子,一些微型微控制器不支持堆栈,最不直接。 并且在某些情况下,无论如何都可以消除堆栈的使用(内联函数或用于函数调用的积极优化,使用寄存器用于局部变量而不是堆栈空间)。

无论如何,对你的问题……这是一个非常主观的问题, 通常归结为一个问题: 你能负担得起吗?

如果你有足够的堆栈空间并且递归不会足以让你的堆栈崩溃,那么递归通常是正确的选择。 不总是,但经常。

但您必须了解您的架构,平台,工具集等,并了解堆栈的大小。 例如,对于许多多任务嵌入式系统,您的堆栈大小是在创建线程/任务时确定的,并且不会“根据需要增长”。 其他简单(嵌入式)系统仅使用单个堆栈,或者可能使用一个“后台”堆栈和一个中断堆栈。 还有一些允许堆栈根据需要在限制范围内增长,具体取决于处理器和操作系统。

如果你来自Java背景,如果这种讨论对你来说很新,我并不感到惊讶。

这个问题没有一个正确的答案。 对于某些问题,递归效果很好。 对于其他人,它没有。

据我所知,C / C ++中没有调用堆栈

为了清楚起见,这是不正确的:我知道C和C ++的所有实现中都有一个调用堆栈。

据我所知,C / C ++中没有调用堆栈,所以我不担心溢出它

咦? 当然, 标准没有讨论调用堆栈,但实际上在大多数(如果不是全部)实现中都有一个。

现在,应该避免递归吗? 首先,众所周知,每个递归函数都可以迭代重写(即没有递归)。 而且,有时迭代解决方案比递归解决方案更快。 但是对于某些任务,例如图中的DFS,递归是如此简单和有用, 除非你有充分的理由不这样做, 否则你不应该避免使用它。 同一个DFS的迭代解决方案几乎一样简单,但需要更多的输入……

我的2 c。

我经常让我的调用栈溢出

那是你的错误。

正确使用时,递归是一个非常有用的构造。 特别是在需要使用可变大小的数据结构集的情况下。 限制递归是微不足道的:

 int recurse(int maxlimit, ...) { if (!--maxlimit) return false; // and throw an exception or something ... return completed ? finalvalue : recurse(maxlimit, ...); } 

递归可以是表达算法的非常优雅的方式。 C / C ++的主要缺点是堆栈溢出的可能性。

这是C / C ++的经验法则:

如果递归不是尾调用,那么深度需要在数据大小上呈亚线性。

例如,如果要递归执行二叉树的DFS,则必须平衡该树,使得递归深度为O(log n)。 这确保没有堆栈溢出。 不要使用非尾递归来遍历链表(O(n)深度)。