我在学校里很难理解递归。每当教授谈到它的时候,我似乎都懂了,但当我自己尝试的时候,它完全震撼了我的大脑。
我整晚都在尝试着解决《Towers of Hanoi》这款游戏,结果完全出乎我的意料。我的课本只有大约30页关于递归的内容,所以它不是很有用。有人知道哪些书籍或资源可以帮助澄清这个话题吗?
我在学校里很难理解递归。每当教授谈到它的时候,我似乎都懂了,但当我自己尝试的时候,它完全震撼了我的大脑。
我整晚都在尝试着解决《Towers of Hanoi》这款游戏,结果完全出乎我的意料。我的课本只有大约30页关于递归的内容,所以它不是很有用。有人知道哪些书籍或资源可以帮助澄清这个话题吗?
当前回答
Ouch. I tried to figure out the Towers of Hanoi last year. The tricky thing about TOH is it's not a simple example of recursion - you have nested recursions which also change the roles of towers on each call. The only way I could get it to make sense was to literally visualize the movement of the rings in my mind's eye, and verbalize what the recursive call would be. I would start with a single ring, then two, then three. I actually ordered the game on the internet. It took me maybe two or three days of cracking my brains to get it.
其他回答
实际上,使用递归是为了降低手头问题的复杂性。你应用递归,直到你达到一个简单的基本情况,可以很容易地解决。这样就可以解决最后一个递归步骤。用这些递归步骤就可以解决最初的问题。
这与其说是一个问题,不如说是一个抱怨。关于递归你有更具体的问题吗?就像乘法一样,人们不会写很多关于它的东西。
说到乘法,想想这个。
问题:
* b是什么?
答:
如果b = 1,就是a。 否则就是a+a*(b-1)
* (b - 1)是什么?请参考上面的问题来解决这个问题。
你的大脑爆炸是因为它进入了无限递归。这是初学者常犯的错误。
信不信由你,你已经理解了递归,你只是被一个常见的,但错误的函数比喻拖了下来:一个小盒子,里面有东西进进出出。
而不是考虑一个任务或过程,比如“在网上找到更多关于递归的知识”。这是递归的,没有问题。要完成这个任务,你可以:
a) Read a Google's result page for "recursion" b) Once you've read it, follow the first link on it and... a.1)Read that new page about recursion b.1)Once you've read it, follow the first link on it and... a.2)Read that new page about recursion b.2)Once you've read it, follow the first link on it and...
如您所见,您已经做了很长一段时间的递归工作,没有出现任何问题。
你会坚持做这个任务多久?永远,直到你的大脑爆炸?当然不是,只要你相信你已经完成了任务,你就会停在一个给定的点上。
当要求你“在网上找到更多关于递归的知识”时,没有必要指定这一点,因为你是一个人,你可以自己推断。
计算机无法推断任何东西,所以你必须包含一个明确的结尾:“在网上找到更多关于递归的知识,直到你理解它或你阅读了最多10页”。
您还推断应该从谷歌的结果页面开始进行“递归”,这也是计算机无法做到的。递归任务的完整描述还必须包括一个显式的起点:
“在网上找到更多关于递归的知识,直到你理解它,或者你已经阅读了最多10页,并从www.google.com/search?q=recursion开始”
要想全面了解,我建议你试试下面这些书:
普通Lisp:符号计算的简单介绍。这是对递归最可爱的非数学解释。 小阴谋家。
构建递归函数的真正数学方法如下:
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.
你在用哪本书?
关于算法的标准教科书是Cormen & Rivest。我的经验是,它很好地教授了递归。
递归是编程中较难掌握的部分之一,虽然它确实需要本能,但它是可以学习的。但它确实需要一个好的描述,好的例子和好的插图。
此外,30页通常是很多的,30页是用一种编程语言编写的。在你从一本普通的书中理解递归之前,不要尝试用C或Java学习递归。