关于循环,递归和栈的一些思考

有一类问题,可以归结为如下形式:

已知两个条件:1,f(n) 和 f(n-1) 的递推关系式; 2,某个f(x) 的具体值。求解:f(n)。

跟高中的某一类数列问题一模一样...

这个问题有两条思路:

a,正向推导:根据 f(x) 可以求解 f(x+1)的值,再求f(x+2),...,求得f(n)。

b,反向推导:根据 f(n) 和 f(n-1) 的关系,以及 f(n-1) 和 f(n-1) 的关系,可以推出 f(n) 和 f(n-2) 的关系,接着推导出 f(n) 和 f(n-3) 的关系,...,直至求出 f(n) 和 f(x) 的关系,最后将 f(x) 的值代入得到 f(n) 的值。

思路a有明确的初值,有明确的迭代次数,每一次迭代求得的都是具体的值,易于用循环实现。

思路b不一样,它每一步求得的是一个关系式,中间结果含有符号表达式,推到最后一步还要回代才能得到数值结果。递归正是这条思路的具体实现。

我们往往觉得比起循环,递归更难以理解,是因为在循环中只要把上一次循环的结果拿到放到这一次循环,不需要管早期的数据;而在递归中,每一次递推,要用到前面出现过的所有数据。数据量大了,对人脑就是一项很重的负担,演算也比较吃力。但计算机是绝妙的工具,在递归程序中,它会自动进行演算、保存数据,只要我们确保初值和递推关系是正确的,并且内存和运算能力足够,就能得到最终结果。

在大多数情况下,循环和递归异曲同工,都能解决问题,也能相互转化。但是在某些情况下,考虑到算法的时间、空间复杂度,我们往往会选择循环;另一些情况下,考虑到可读性、实现的难易程度,我们会选择递归。

我个人认为所有的递归实现都可以改为循环。我的理由如下:

在计算机底层,函数调用是通过“保护现场->提升堆栈->跳转到函数对应的指令地址->执行指令->恢复堆栈->恢复现场”来实现的。对于同一个函数,整个过程都是相同的!不同的只是某些实参的值。这样的话,我们可以利用栈和循环,模仿系统调用函数的过程,把递归函数改写为循环。

有空的时候我改写几个试试!

猜你喜欢

转载自blog.csdn.net/liusiweix/article/details/84038747