[b]什么是递归函数/方法?[/b]
任何一个方法既可以调用其他方法也可以调用自己,而当这个方法调用自己时,我们就叫它递归函数或递归方法。
[b]通常递归有两个特点[/b]:
1. 递归方法一直会调用自己直到某些条件被满足
2. 递归方法会有一些参数,而它会把一些新的参数值传递给自己。
那什么是递归函数?函数和方法没有本质区别,但函数仅在类的内部使用。以前C#中只有方法,从.NET 3.5开始才有了匿名函数。
所以,我们最好叫递归方法,而非递归函数,本文中将统一称之为递归。
[b]在应用程序中为什么要使用递归?何时使用递归?如何用?[/b]
“写任何一个程序可以用赋值和if-then-else语句表示出来,而while语句则可以用赋值、if-then-else和递归表示出来。”(出自Ellis Horowitz的《数据结构基础(C语言版)》 - Fundamentals of Data Structure in C)
递归解决方案对于复杂的开发来说很方便,而且十分强大,但由于频繁使用调用栈(call stack)可能会引起性能问题(有些时候性能极差)。
我们来看一看下面这个图:
[url=http://images.cnblogs.com/cnblogs_com/tonyqus/201212/201212240441113850.jpg][img]http://files.jb51.net/file_images/article/201212/2012122715025732.jpg[/img]
[/url]
[b]调用栈图示[/b]
下面我打算介绍一些例子来帮助你更好的理解递归的风险和回报。
[b]1. 阶乘[/b]
阶乘(!)是小于某个数的所有正整数的乘积。
0! = 1
1! = 1
2! = 2 * 1! = 2
3! = 3 * 2! = 6
...
n! = n * (n - 1)!
下面是计算阶乘的一种实现方法(没有递归):
[url=http://images.cnitblog.com/blog/4860/201212/25111632-667feb0957924998837bd6d0490ce9d1.png][img]http://files.jb51.net/file_images/article/201212/2012122715025733.png[/img]
[/url]
我在供你下载的示范项目中使用了递归,通过这个项目你可以搜索某个路径,并获得当前文件夹和其子文件夹中所有文件的路径。
private Dictionary<string, string> errors = new Dictionary<string, string>();
private List<string> result = new List<string>();
private void SearchForFiles(string path)
{
try
{
foreach (string fileName in Directory.GetFiles(path))//Gets all files in the current path
{
result.Add(fileName);
}
foreach (string directory in Directory.GetDirectories(path))//Gets all folders in the current path
{
SearchForFiles(directory);//The methods calls itself with a new parameter, here!
}
}
catch (System.Exception ex)
{
errors.Add(path, ex.Message);//Stores Error Messages in a dictionary with path in key
}
}
这个方法似乎不需要满足任何条件,因为每个目录如果没有子目录,会自动遍历所有子文件。
[b]总结[/b]
我们其实可以用递推算法来替代递归,且性能会更好些,但我们可能需要更多的时间开销和非递归函数。但关键是我们必须根据场景选择最佳实现方式。
James MaCaffrey博士认为尽量不要使用递归,除非实在没有办法。你可以读一下他的文章。
[b]我认为[/b]:
A) 如果性能是非常重要的,请避免使用递归
B)如果递推方式不是很复杂的,请避免使用递归
C) 如果A和B都不满足,请不要犹豫,用递归吧。
[b]例如[/b]:
第一节(阶乘):这里用递推并不复杂,那么就避免用递归。
第二节(Fibonacci):像这样的递归并不被推荐。
当然,我并不是要贬低递归的价值,我记得人工智能中的重要一章有个极小化极大算法(Minimax algorithm),全部是用递归实现的。
但是如果你决定使用队规方法,你最好尝试用存储来优化它。
版权声明:本文由作者Tony Qu原创, 未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。