将递归算法转换为迭代算法的设计模式
是否有任何通用启发法、提示、技巧或常见设计范例可用于将递归算法转换为迭代算法?我知道这是可以做到的,我想知道这样做时是否有值得记住的做法。
Are there any general heuristics, tips, tricks, or common design paradigms that can be employed to convert a recursive algorithm to an iterative one? I know it can be done, I'm wondering if there are practices worth keeping in mind when doing so.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您通常可以完全保留递归算法的原始结构,但通过使用尾调用并更改为连续传递来避免堆栈,如此博客条目。 (我真的应该编写一个更好的独立示例。)
You can often entirely preserve the original structure of a recursive algorithm, but avoid the stack, by employing tail calls and changing to continuation-passing, as suggested by this blog entry. (I should really cook up a better standalone example.)
我在用迭代算法替换递归算法的过程中使用的一种常用技术通常是使用堆栈,将传递给递归函数的参数推送。
查看以下文章:
A common technique that I use where I'm on the process of replace a recursive algorithm by an iterative one is generally to use a stack, pushing the parameters that are being passed to the recursive function.
Check the following articles:
常见的做法是管理一个 LIFO 堆栈,该堆栈保留“剩余要做的事情”的运行列表,并在 while 循环中处理整个过程,该循环一直持续到列表为空为止。
使用这种模式,真正的递归模型中的递归调用将被替换为
- 将当前(部分完成)任务的“上下文”推入堆栈,
- 将新任务(促使递归的任务)推入堆栈
- 并“继续”(即跳到开头)while 循环。
在循环头部附近,逻辑弹出最近插入的上下文,并在此基础上开始工作。
实际上,这只是将原本保存在“系统”堆栈上的嵌套堆栈帧中的信息“移动”到应用程序管理的堆栈容器。然而,这是一个改进,因为这个堆栈容器可以分配在任何地方(递归限制通常与“系统”堆栈中的限制相关)。因此,本质上完成了相同的工作,但“堆栈”的显式管理允许在单个循环构造中进行,而不是在递归调用中进行。
A common practice is to manage a LIFO stack that keeps a running list of what "remains to be done", and to handle the whole process in a while loop which continues until the list is empty.
With this pattern, what would be a recursion call in the true recursion model is replaced by
- a pushing of current (partially finished) task's "context" onto the stack,
- a pushing of the new task (the one which prompted recursion) onto the stack
- and to "continue" (i.e. jump to the beginning of) the while loop.
Near the head of the loop, the logic pops the most recently inserted context, and starts work on this basis.
Effectively this merely "moves" information which would have otherwise been kept in nested stackframes on the "system" stack, to an application-managed stack container. It is an improvement however, for this stack container can be allocated anywhere (the recursion limit is typically tied to limits in the "system" stack). Therefore essentially the same work gets done, but the explicit management of a "stack" allows this to take place within a single loop construct rather than recursive calls.
通常,一般递归可以用尾递归代替,通过在累加器中收集部分结果并通过递归调用将其向下传递。尾递归本质上是迭代,递归调用可以实现为跳转。
例如,阶乘的标准通用递归定义
可以替换为
and ,
它是尾递归的。它是一样的
Often general recursion can be replaced by tail recursion, by collecting partial results in an accumulator and passing it down with the recursive call. Tail recursion is essentially iterative, the recursive call can be implemented as a jump.
For example, the standard general recursive definition of factorial
can be replaced by
and
which is tail recursive. It is the same as
查看这些链接以获取性能示例
递归 VS 迭代(循环) :速度和速度内存比较
和
用迭代替换递归
和
递归与迭代
Have a look at these links for performance examples
Recursion VS Iteration (Looping) : Speed & Memory Comparison
and
Replace Recursion with Iteration
and
Recursion vs Iteration
我通常从基本情况开始(每个递归函数都有一个)并向后工作,如有必要,将结果存储在缓存(数组或哈希表)中。
递归函数通过解决较小的子问题并使用它们来解决较大的问题实例来解决问题。每个子问题也被进一步分解,依此类推,直到子问题很小以至于解决方案变得微不足道(即基本情况)。
这个想法是从基本案例(或多个基本案例)开始,并使用它来构建更大案例的解决方案,然后使用它们来构建更大的案例,依此类推,直到整个问题得到解决。这不需要堆栈,并且可以通过循环来完成。
一个简单的例子(Python):
I generally start from the base case (every recursive function has one) and work my way backwards, storing the results in a cache (array or hashtable) if necessary.
Your recursive function solves a problem by solving smaller subproblems and using them to solve the bigger the instance of the problem. Each subproblem is also broken down further and so on until the subproblem is so small that the solution is trivial (i.e. the base case).
The idea is to start at the base case(or base cases) and use that to build the solution for larger cases, and then use those to build even larger cases and so on, until the whole problem is solved. This does not require a stack, and can be done with loops.
A simple example (in Python):
一种模式是尾递归:
维基。
One pattern is Tail Recursion:
Wiki.