转载链接:http://blog.csdn.net/vagrxie/article/details/8470798
理解递归
在初学递归的时候, 看到一个递归实现, 我们总是难免陷入不停的回溯验证之中, 因为回溯就像反过来思考迭代, 这是我们习惯的思维方式, 但是实际上递归不需要这样来验证. 比如, 另外一个常见的例子是阶乘的计算. 阶乘的定义: “一个正整数的阶乘(英语:factorial)是所有小于或等于该数的正整数的积,并且0的阶乘为1。” 以下是Ruby的实现:
def factorial(n) if n <= 1 then return 1 else return n * factorial(n - 1) end end
我们怎么判断这个阶乘的递归计算是否是正确的呢? 先别说测试, 我说我们读代码的时候怎么判断呢?
回溯的思考方式是这么验证的, 比如当n = 4时, 那么factoria(4)
等于4 * factoria(3)
, 而factoria(3)
等于3 * factoria(2)
, factoria(2)
等于2 * factoria(1)
, 等于2 * 1
, 所以factoria(4)
等于4 * 3 * 2 * 1
. 这个结果正好等于阶乘4的迭代定义.
用回溯的方式思考虽然可以验证当n = 某个较小数值是否正确, 但是其实无益于理解.
Paul Graham提到一种方法, 给我很大启发, 该方法如下:
- 当n=0, 1的时候, 结果正确.
- 假设函数对于n是正确的, 函数对n+1结果也正确. (假设函数对于n-1是正确的, 函数对n结果也正确. )
如果这两点是成立的,我们知道这个函数对于所有可能的n都是正确的。对于2,我的理解是就是假设前n-1或n已经是正确的或者说是完成要求的了,现在着手对n或n-1进行操作
这种方法很像数学归纳法, 也是递归正确的思考方式, 事实上, 阶乘的递归表达方式就是1!=1,n!=(n-1)!×n
(见wiki). 当程序实现符合算法描述的时候, 程序自然对了, 假如还不对, 那是算法本身错了…… 相对来说, n,n+1的情况为通用情况, 虽然比较复杂, 但是还能理解, 最重要的, 也是最容易被新手忽略的问题在于第1点, 也就是基本用例(base case)要对. 比如, 上例中, 我们去掉if n <= 1
的判断后, 代码会进入死循环, 永远不会结束.