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