递归的理解(二)

迭代的是人,递归的是神;

理解递归

在初学递归的时候, 看到一个递归实现,我们总是难免陷入不停的回溯验证之中, 因为回溯就像反过来思考迭代, 这是我们习惯的思维方式, 但是实际上递归不需要这样来验证.

我们怎么判断这个阶乘的递归计算是否是正确的呢? 先别说测试, 我说我们读代码的时候怎么判断呢?

思考方式1:回溯的思考方式是这么验证的, 比如当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 = 某个较小数值是否正确, 但是其实无益于理解.

思考方式2

当n=0, 1的时候, 结果正确.

假设函数对于n是正确的, 函数对n+1结果也正确.

如果这两点是成立的,我们知道这个函数对于所有可能的n都是正确的。

这种方法很像数学归纳法, 也是递归正确的思考方式, 事实上, 阶乘的递归表达方式就是1!=1,n!=(n-1)!×n;当程序实现符合算法描述的时候, 程序自然对了, 假如还不对,那是算法本身错了…… 相对来说, n,n+1的情况为通用情况, 虽然比较复杂, 但是还能理解, 最重要的, 也是最容易被新手忽略的问题在于第1点,也就是基本用例(base case)要对.比如, 上例中, 我们去掉if n <= 1的判断后, 代码会进入死循环, 永远不会结束.

使用递归

1.    怎样找到一个问题的递归算法:

(1)  必须要示范如何解决问题的一般情况, 通过将问题切分成有限小并更小的子问题.

(2)  必须要示范如何通过有限的步骤, 来解决最小的问题(基本用例).

如果这两件事完成了, 那问题就解决了. 因为递归每次都将问题变得更小, 而一个有限的问题终究会被解决的, 而最小的问题仅需几个有限的步骤就能解决.

汉诺塔的递归实现:

计算机科学的新学生通常难以理解递归程序设计的概念。递归思想之所以困难,原因在于它非常像是循环推理;它也不是一个直观的过程;当我们指挥别人做事的时候,我们极少会递归地指挥他们。

停止的位置称为:基线条件(base case基线条件是递归程序的最底层位置,在此位置时没有必要再进行操作,可以直接返回一个结果所有递归程序都必须至少拥有一个基线条件,而且 必须确保它们最终会达到某个基线条件;

使用归纳定义:

有时候,编写递归程序时难以获得更简单的子问题;不过,使用归纳定义的数据集 可以令子问题的获得更为简单; 使用归纳数据编写递归过程非常简单。注意,与我们的递归程序非常类似,链表的定义也包括一个基线条件 — 在这里是 NULL 指针由于 NULL 指针会结束一个链表,所以我们也可以使用 NULL 指针条件作为基于链表的很多递归程序的基线条件

 

尾递归:

1.    对于递归函数的使用,人们所关心的一个问题是栈空间的增长。确实,随着被调用次数的增加,某些种类的递归函数会线性地增加栈空间的使用 —— 不过,有一类函数,即尾部递归函数,不管递归有多深,栈的大小都保持不变。尾递归属于线性递归,更准确的说是线性递归的子集。

2.    函数所做的最后一件事情是一个函数调用(递归的或者非递归的),这被称为尾部调用;使用尾部调用的递归称为尾部递归。

3.    当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。编译器可以做到这点,因为递归调用是当前活跃期内最后一条待执行的语句,于是当这个调用返回时栈帧中并没有其他事情可做,因此也就没有保存栈帧的必要了。通过覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了,这使得实际的运行效率会变得更高。

4.    要使调用成为真正的尾部调用,在尾部调用函数返回之前,对其结果不能执行任何其他操作;由于在函数中不再做任何事情,那个函数的实际的栈结构也就不需要了;

(1)  函数在尾部被调用之后,还需要使用哪个本地变量?哪个也不需要;

(2)  会对返回的值进行什么处理?什么处理也没有;

(3)  传递到函数的哪个参数将会被使用?哪个都没有。  







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值