在多年的编程中,我已经使用了不少递归来解决简单的问题,可是我彻底意识到有时因为内存/速度问题须要迭代。 node
所以,在好久之前的某个时候,我去尝试查找是否存在将通用递归方法转换为迭代的任何“模式”或教科书方法,却一无所得。 或至少没有什么我能记住的会有所帮助。 编程
递归不过是从另外一个函数调用另外一个函数的过程,只有此过程是经过单独调用一个函数来完成的。 众所周知,当一个函数调用另外一个函数时,第一个函数保存其状态(其变量),而后将控件传递给被调用的函数。 能够经过使用相同的变量名来调用被调用函数,例如fun1(a)能够调用fun2(a)。 当咱们进行递归调用时,没有新的事情发生。 一个函数经过传递相同的类型和类似的名称变量来调用自身(可是很明显,存储在变量中的值是不一样的,只是名称保持不变。)。 可是,在每次调用以前,函数都会保存其状态,而且保存过程将继续。 保存在堆栈上。 函数
如今,堆栈开始播放了。 spa
所以,若是您编写一个迭代程序并每次将状态保存在堆栈上,而后在须要时从堆栈中弹出值,那么您已成功将递归程序转换为迭代程序! rest
证实是简单和分析的。 code
在递归中,计算机维护堆栈,而在迭代版本中,您将必须手动维护堆栈。 递归
考虑一下,只需将深度优先搜索(在图形上)递归程序转换为dfs迭代程序。 内存
祝一切顺利! 开发
一般,将堆栈溢出用于递归函数的技术称为蹦床技术,这是Java开发人员普遍采用的技术。 get
可是,对于C#,这里有一个小的辅助方法,能够将递归函数变成迭代的,而无需更改逻辑或使代码难以理解。 C#是一种很棒的语言,它可能带来使人惊奇的东西。
它经过使用辅助方法包装方法的某些部分来工做。 例如如下递归函数:
int Sum(int index, int[] array) { //This is the termination condition if (int >= array.Length) //This is the returning value when termination condition is true return 0; //This is the recursive call var sumofrest = Sum(index+1, array); //This is the work to do with the current item and the //result of recursive call return array[index]+sumofrest; }
变成:
int Sum(int[] ar) { return RecursionHelper<int>.CreateSingular(i => i >= ar.Length, i => 0) .RecursiveCall((i, rv) => i + 1) .Do((i, rv) => ar[i] + rv) .Execute(0); }
努力进行递归调用Tail Recursion (递归,其中最后一条语句是递归调用)。 一旦有了这些,将其转换为迭代一般很是容易。
在Google上搜索“继续传递样式”。 有一个转换为尾部递归样式的通用过程。 还有将尾递归函数转换为循环的通用过程。
要寻找的一种模式是在函数末尾进行递归调用(所谓的尾递归)。 能够轻松地将其替换一下子。 例如,函数foo:
void foo(Node* node) { if(node == NULL) return; // Do something with node... foo(node->left); foo(node->right); }
以对foo的调用结束。 能够替换为:
void foo(Node* node) { while(node != NULL) { // Do something with node... foo(node->left); node = node->right; } }
这样就消除了第二个递归调用。