recursion函数的例子
任何人都可以build议说明recursion函数的编程示例吗? 有像斐波那契系列和河内塔这样的老马,除此之外的任何东西都会很有趣。
这个插图是英文的,而不是一个实际的编程语言,但是用非技术的方式解释这个过程是很有用的:
一个小孩睡不着,所以妈妈讲了一个小青蛙的故事, 谁也睡不着,所以青蛙的妈妈讲了一个小熊的故事, 谁不能睡觉,所以熊的妈妈讲了一个关于一个小黄鼠狼的故事 谁睡着了 ...小熊睡着了; 小青蛙睡着了; ...孩子睡着了。
为了理解 recursion ,首先必须理解recursion 。
recursion的经验法则是“使用recursion,当且仅当您的任务分裂成两个或更多相似的任务时每次迭代”。
所以斐波纳契不是一个recursion应用的好例子,而河内是一个很好的例子。
所以大多数recursion的好例子都是在不同的树中遍历树。
例如:图遍历 – 访问节点再也不会被有效访问的要求使graphics成为一棵树(一棵树是没有简单周期的连通图)
分而治之algorithm(快速sorting,合并sorting) – “划分”之后的部分构成子节点,“征服”构成从父节点到子节点的边。
如何testing一个string作为回文?
bool isPalindrome(char* s, int len) { if(len < 2) return TRUE; else return s[0] == s[len-1] && isPalindrome(&s[1], len-2); }
当然,你可以更有效地使用循环。
写一个recursion下降分析器 !
另外两个“常见的嫌疑人”是Quicksort和MergeSort
从math的世界,有阿克曼function :
Ackermann(m, n) { if(m==0) return n+1; else if(m>0 && n==0) return Ackermann(m-1, 1); else if(m>0 && n>0) return Ackermann(m-1, Ackermann(m, n-1)); else throw exception; //not defined for negative m or n }
它总是终止,但即使是非常小的input,也会产生非常大的结果。 阿克曼(4,2),例如,返回2 65536 – 3。
解释器的devise模式是一个很好的例子,因为很多人都没有发现recursion。 维基百科文章中列出的示例代码很好地说明了这可以如何应用。 然而,仍然实现解释器模式的更基本的方法是嵌套列表的ToString
函数:
class List { public List(params object[] items) { foreach (object o in items) this.Add(o); } // Most of the implementation omitted … public override string ToString() { var ret = new StringBuilder(); ret.Append("( "); foreach (object o in this) { ret.Append(o); ret.Append(" "); } ret.Append(")"); return ret.ToString(); } } var lst = new List(1, 2, new List(3, 4), new List(new List(5), 6), 7); Console.WriteLine(lst); // yields: // ( 1 2 ( 3 4 ) ( ( 5 ) 6 ) 7 )
(是的,我知道在上面的代码中find解释器模式是不容易的,如果你期望一个叫做Eval
的函数……但是真的,解释器模式并不告诉我们这个函数被调用了什么,甚至是它和GoF书明确列出上述作为所述模式的示例。)
在我看来,recursion很好理解,但是大多数可以使用recursion的解决scheme也可以使用迭代来完成,并且迭代效率更高。
这就是说,在嵌套树(如ASP.NET或Winforms)中查找控件的recursion方法如下:
public Control FindControl(Control startControl, string id) { if (startControl.Id == id) return startControl if (startControl.Children.Count > 0) { foreach (Control c in startControl.Children) { return FindControl(c, id); } } return null; }
这是来自文件系统世界的一个实用的例子。 此实用程序recursion计算指定目录下的文件。 (我不记得为什么,但是我确实需要很久以前的东西…)
public static int countFiles(File f) { if (f.isFile()){ return 1; } // Count children & recurse into subdirs: int count = 0; File[] files = f.listFiles(); for (File fileOrDir : files) { count += countFiles(fileOrDir); } return count; }
(请注意,在Java中,一个File
实例可以表示一个普通的文件或者一个目录,这个工具从count中排除目录。)
一个普通的现实世界的例子是,例如来自Commons IO库的FileUtils.deleteDirectory()
; 请参阅API文档和来源 。
一个真实的例子是“物料成本计算”问题。
假设我们有一家生产最终产品的制造公司。 每个产品都可以通过零件清单和组装这些零件所需的时间来描述。 例如,我们从一个箱子,电机,卡盘,开关和电线制造手持式电钻,需要5分钟的时间。
给定每分钟的标准劳动力成本,制造每种产品需要多less成本?
哦,顺便说一下,有些零件(如电线)是购买的,所以我们直接了解他们的成本。
但是我们自己实际制造了一些零件。 我们从一个shell,一个定子,一个转子,一个轴和轴承中制造一个电机,花费15分钟。
而我们使定子和转子的冲压件和电线,…
因此,确定成品的成本实际上相当于遍历树,该树代表了我们stream程中的所有部件之间的关系。 用recursionalgorithm很好地expression了这一点。 它当然也可以迭代地完成,但是核心思想与自己动手记账混在一起,所以目前还不清楚。
我知道的最好的例子是Knuth的男人或男孩testing 。 和recursion一样,它使用嵌套函数定义(闭包),函数引用和常量/函数二元(按名称调用)的Algol特性。
正如其他人已经说过的,很多规范recursion的例子都是学术的。
过去遇到的一些实际用途是:
1 – 浏览树结构,如文件系统或registry
2 – 操作可能包含其他容器控件的容器控件(如面板或combobox)
我个人最喜欢的是二进制search
编辑:另外,树遍历。 例如,走下一个文件夹文件结构。
通过Guido van Rossum 实现图在Python中有一些recursion函数来查找图中两个节点之间的path。
我最喜欢的sorting, 合并sorting
(最喜欢的,因为我可以记住的algorithm,是不是太糟糕的性能明智的)
- 阶乘
- 深入遍历树(在文件系统,游戏空间或任何其他情况下)
如何扭转一个string?
void rev(string s) { if (!s.empty()) { rev(s[1..s.length]); } print(s[0]); }
了解这有助于理解recursion。
下面是我在这个网站上发布的一个示例,以前recursion生成一个菜单树: recursion示例
如何处理列表 ,如:
- map(和andmap,ormap)
- 倍(foldl,foldr)
- 过滤
- 等等…
曾几何时,不久之前,小学的孩子们用Logo和Turtle Graphics学习了recursion。 http://en.wikipedia.org/wiki/Turtle_graphics
recursion也是通过彻底的试验来解决难题的好方法。 有一种被称为“填充”(Google)的谜题,其中有一个像填字游戏一样的网格,而且没有线索,也没有编号的方块。 我曾经写过一个程序,使用recursion来解决难题,以确保已知的解决scheme是独一无二的。
recursion函数对于使用recursion定义的数据types非常有用:
- 自然数是零或另一个自然数的inheritance者
- 列表是空的列表或另一个列表中包含前面的元素
- 树是具有一些数据和零个或更多其他子树的节点
等等。
将电子表格列索引转换为列名称。
这比听起来更棘手,因为电子表格列不能正确处理“0”数字。 例如,如果从Z到AA递增时,将AZ用作数字,那么就像从9到11或9到00而不是10(取决于A是1还是0)。 即使是微软支持的例子也会因为AAA以上的东西而出错。
recursion解决scheme的工作原理是因为您可以在这些新数字边界上recursion。 这个实现是在VB.Net,并把第一列('A')作为索引1。
Function ColumnName(ByVal index As Integer) As String Static chars() As Char = {"A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c, "J"c, "K"c, "L"c, "M"c, "N"c, "O"c, "P"c, "Q"c, "R"c, "S"c, "T"c, "U"c, "V"c, "W"c, "X"c, "Y"c, "Z"c} index -= 1 'adjust index so it matches 0-indexed array rather than 1-indexed column' Dim quotient As Integer = index \ 26 'normal / operator rounds. \ does integer division' If quotient > 0 Then Return ColumnName(quotient) & chars(index Mod 26) Else Return chars(index Mod 26) End If End Function