我几乎可以找到有关递归的每篇文章,其中包括阶乘或斐波那契数的示例,它们是:
- 数学
- 在现实生活中无用
是否有一些有趣的非数学代码示例来教授递归?
我在考虑分而治之算法,但它们通常涉及复杂的数据结构。
我几乎可以找到有关递归的每篇文章,其中包括阶乘或斐波那契数的示例,它们是:
是否有一些有趣的非数学代码示例来教授递归?
我在考虑分而治之算法,但它们通常涉及复杂的数据结构。
Answers:
目录/文件结构是递归用法的最佳示例,因为每个人都可以在开始之前就了解它们,但是任何涉及树状结构的事物都可以使用。
void GetAllFilePaths(Directory dir, List<string> paths)
{
foreach(File file in dir.Files)
{
paths.Add(file.Path);
}
foreach(Directory subdir in dir.Directories)
{
GetAllFilePaths(subdir, paths)
}
}
List<string> GetAllFilePaths(Directory dir)
{
List<string> paths = new List<string>();
GetAllFilePaths(dir, paths);
return paths;
}
寻找涉及树形结构的事物。一棵树相对容易掌握,并且与线性数据结构(例如列表)相比,递归解决方案的优势变得更加明显。
要考虑的事情:
这些都与实际的实际场景有关,并且都可以用于具有实际意义的应用程序中。
https://stackoverflow.com/questions/105838/real-world-examples-of-recursion
https://stackoverflow.com/questions/2085834/how-did-you-practically-use-recursion
https://stackoverflow.com/questions/126756/examples-of-recursive-functions
QuickSort将是第一个让人想到的。二进制搜索也是一个递归问题。除此之外,还存在一整类问题,当您开始使用递归时,解决方案几乎是免费的。
排序,在Python中递归定义。
def sort( a ):
if len(a) == 1: return a
part1= sort( a[:len(a)//2] )
part2= sort( a[len(a)//2:] )
return merge( part1, part2 )
合并,以递归方式定义。
def merge( a, b ):
if len(b) == 0: return a
if len(a) == 0: return b
if a[0] < b[0]:
return [ a[0] ] + merge(a[1:], b)
else:
return [ b[0] ] + merge(a, b[1:])
线性搜索,以递归方式定义。
def find( element, sequence ):
if len(sequence) == 0: return False
if element == sequence[0]: return True
return find( element, sequence[1:] )
二进制搜索,以递归方式定义。
def binsearch( element, sequence ):
if len(sequence) == 0: return False
mid = len(sequence)//2
if element < mid:
return binsearch( element, sequence[:mid] )
else:
return binsearch( element, sequence[mid:] )
从某种意义上讲,递归就是解决问题的方法,即将问题空间缩小为一个较小的空间,以帮助找到一个简单问题的解决方案,然后通常回头重建原始问题以构成正确的答案。
一些不涉及数学的递归教学示例(至少我在大学时代记得的那些问题):
这些是使用回溯解决问题的示例。
其他问题是人工智能领域的经典问题:使用深度优先搜索,寻路,规划。
所有这些问题都涉及某种“复杂”的数据结构,但是如果您不想用数学(数字)来教它,那么您的选择可能会更加有限。Yoy可能想开始使用基本数据结构(如链表)进行教学。例如,使用列表表示自然数:
0 =空列表1 =具有一个节点的列表。2 =列出2个节点。...
然后根据此数据结构定义两个数字的总和,如下所示:空+ N = N Node(X)+ N = Node(X + N)
回文检测器:
以字符串开头:“ ABCDEEDCBA”如果开始和结束字符相等,则递归并检查“ BCDEEDCB”,等等。
在函数式编程语言中,当没有高阶函数可用时,将使用递归而不是命令式循环,以避免可变状态。
F#是一种不纯净的功能语言,它同时允许两种样式,因此我将在此处进行比较。以下是列表中所有数字的总和。
具有可变变量的命令式循环
let xlist = [1;2;3;4;5;6;7;8;9;10]
let mutable sum = 0
for x in xlist do
sum <- sum + x
没有可变状态的递归循环
let xlist = [1;2;3;4;5;6;7;8;9;10]
let rec loop sum xlist =
match xlist with
| [] -> sum
| x::xlist -> loop (sum + x) xlist
let sum = loop 0 xlist
请注意,这种聚合是在高阶函数中捕获的List.fold
,可以将其写为List.fold (+) 0 xlist
,甚至可以更简单地用便利函数List.sum
just 编写List.sum xlist
。
我在游戏AI中大量使用了递归。用C ++编写时,我使用了一系列约7个函数,这些函数按顺序相互调用(第一个函数可以绕过所有这些函数,而是调用另外2个函数链)。任一个链中的最终函数再次调用第一个函数,直到我要搜索的剩余深度变为0,在这种情况下,最终函数将调用我的评估函数并返回位置得分。
多种功能使我可以轻松地根据玩家的决定或游戏中的随机事件进行分支。我会尽可能使用传递引用,因为我要传递非常大的数据结构,但是由于游戏的结构方式,很难在搜索中进行“撤消”操作,因此我会在某些函数中使用按值传递,以保持原始数据不变。因此,事实证明切换到基于循环的方法而不是递归方法太困难了。
您可以看到此类程序的非常基本的概述,请参阅https://secure.wikimedia.org/wikipedia/en/wiki/Minimax#Pseudocode
商业中一个非常好的现实生活例子就是所谓的“物料清单”。这是代表组成成品的所有组件的数据。例如,让我们使用自行车。自行车具有车把,车轮,车架等。每个组件都可以包含子组件。例如,车轮可以具有辐条,气门杆等。因此,通常以树状结构表示。
现在,您经常需要递归来查询有关BOM的任何汇总信息或更改BOM中的元素。
class BomPart
{
public string PartNumber { get; set; }
public string Desription { get; set; }
public int Quantity { get; set; }
public bool Plastic { get; set; }
public List<BomPart> Components = new List<BomPart>();
}
还有一个示例递归调用...
static int ComponentCount(BomPart part)
{
int subCount = 0;
foreach(BomPart p in part.Components)
subCount += ComponentCount(p);
return part.Quantity * Math.Max(1,subCount);
}
显然,BomPart类将具有更多的字段。您可能需要弄清楚您有多少个塑料组件,制造一个完整零件需要多少人工等。所有这些都回到了递归在树结构上的有用性。
家庭关系是一个很好的例子,因为每个人都能直观地理解它们:
ancestor(joe, me) = (joe == me)
OR ancestor(joe, me.father)
OR ancestor(joe, me.mother);
||
为OR
。
我使用递归程序解决了骑士模式(在棋board上)的问题。您应该移动骑士,以使骑士触及除几个标记正方形之外的每个正方形。
您只需:
mark your "Current" square
gather a list of free squares that are valid moves
are there no valid moves?
are all squares marked?
you win!
for each free square
recurse!
clear the mark on your current square.
return.
通过在这样的树中测试未来的可能性,可以处理多种“超前思考”方案。