我在学校里很难理解递归。每当教授谈到它的时候,我似乎都懂了,但当我自己尝试的时候,它完全震撼了我的大脑。
我整晚都在尝试着解决《Towers of Hanoi》这款游戏,结果完全出乎我的意料。我的课本只有大约30页关于递归的内容,所以它不是很有用。有人知道哪些书籍或资源可以帮助澄清这个话题吗?
我在学校里很难理解递归。每当教授谈到它的时候,我似乎都懂了,但当我自己尝试的时候,它完全震撼了我的大脑。
我整晚都在尝试着解决《Towers of Hanoi》这款游戏,结果完全出乎我的意料。我的课本只有大约30页关于递归的内容,所以它不是很有用。有人知道哪些书籍或资源可以帮助澄清这个话题吗?
当前回答
递归
方法A调用方法A调用方法A,最终这些方法A中的一个不会调用并退出,但这是递归,因为有东西调用了它自己。
递归的例子,我想打印出硬盘驱动器上的每个文件夹名称:(在c#中)
public void PrintFolderNames(DirectoryInfo directory)
{
Console.WriteLine(directory.Name);
DirectoryInfo[] children = directory.GetDirectories();
foreach(var child in children)
{
PrintFolderNames(child); // See we call ourself here...
}
}
其他回答
Common Lisp中的简单递归示例:
MYMAP对列表中的每个元素应用一个函数。
1)空列表没有元素,所以我们返回空列表-()和NIL都是空列表。
2)将函数应用到第一个列表,对列表的其余部分调用MYMAP(递归调用),并将两个结果合并到一个新列表中。
(DEFUN MYMAP (FUNCTION LIST)
(IF (NULL LIST)
()
(CONS (FUNCALL FUNCTION (FIRST LIST))
(MYMAP FUNCTION (REST LIST)))))
让我们观察跟踪执行。在输入函数时,输出参数。在退出函数时,输出结果。对于每个递归调用,输出将按级别缩进。
这个例子对列表(1 2 3 4)中的每个数字调用SIN函数。
Command: (mymap 'sin '(1 2 3 4))
1 Enter MYMAP SIN (1 2 3 4)
| 2 Enter MYMAP SIN (2 3 4)
| 3 Enter MYMAP SIN (3 4)
| | 4 Enter MYMAP SIN (4)
| | 5 Enter MYMAP SIN NIL
| | 5 Exit MYMAP NIL
| | 4 Exit MYMAP (-0.75680256)
| 3 Exit MYMAP (0.14112002 -0.75680256)
| 2 Exit MYMAP (0.9092975 0.14112002 -0.75680256)
1 Exit MYMAP (0.841471 0.9092975 0.14112002 -0.75680256)
这是我们的结果:
(0.841471 0.9092975 0.14112002 -0.75680256)
要理解递归,你只需要看看洗发水瓶上的标签:
function repeat()
{
rinse();
lather();
repeat();
}
这样做的问题是没有终止条件,递归将无限重复,或者直到洗发水或热水用完为止(外部终止条件,类似于吹你的堆栈)。
要向一个六岁的孩子解释递归,首先要向一个五岁的孩子解释,然后再等一年。
实际上,这是一个有用的反例,因为递归调用应该更简单,而不是更难。向一个5岁的孩子解释递归就更难了,尽管你可以在0点停止递归,但你没有简单的解决方案来向一个0岁的孩子解释递归。
要使用递归解决一个问题,首先将其细分为一个或多个可以用相同方法解决的更简单的问题,然后当问题简单到无需进一步递归就可以解决时,您可以返回到更高的级别。
事实上,这是用递归方法来解决问题的递归定义。
递归函数只是一个函数,它可以根据需要多次调用自己。如果您需要多次处理某件事,但不确定实际需要多少次,那么它就很有用。在某种程度上,你可以把递归函数看作是一种循环。然而,就像循环一样,您需要指定中断流程的条件,否则它将变得无限。
构建递归函数的真正数学方法如下:
1:假设你有一个函数对f(n-1)是正确的,构造f使f(n)是正确的。 2:构造f,使得f(1)是正确的。
This is how you can prove that the function is correct, mathematically, and it's called Induction. It is equivalent to have different base cases, or more complicated functions on multiple variables). It is also equivalent to imagine that f(x) is correct for all x Now for a "simple" example. Build a function that can determine if it is possible to have a coin combination of 5 cents and 7 cents to make x cents. For example, it's possible to have 17 cents by 2x5 + 1x7, but impossible to have 16 cents. Now imagine you have a function that tells you if it's possible to create x cents, as long as x < n. Call this function can_create_coins_small. It should be fairly simple to imagine how to make the function for n. Now build your function: bool can_create_coins(int n) { if (n >= 7 && can_create_coins_small(n-7)) return true; else if (n >= 5 && can_create_coins_small(n-5)) return true; else return false; } The trick here is to realize that the fact that can_create_coins works for n, means that you can substitute can_create_coins for can_create_coins_small, giving: bool can_create_coins(int n) { if (n >= 7 && can_create_coins(n-7)) return true; else if (n >= 5 && can_create_coins(n-5)) return true; else return false; } One last thing to do is to have a base case to stop infinite recursion. Note that if you are trying to create 0 cents, then that is possible by having no coins. Adding this condition gives: bool can_create_coins(int n) { if (n == 0) return true; else if (n >= 7 && can_create_coins(n-7)) return true; else if (n >= 5 && can_create_coins(n-5)) return true; else return false; } It can be proven that this function will always return, using a method called infinite descent, but that isn't necessary here. You can imagine that f(n) only calls lower values of n, and will always eventually reach 0. To use this information to solve your Tower of Hanoi problem, I think the trick is to assume you have a function to move n-1 tablets from a to b (for any a/b), trying to move n tables from a to b.