参考:http://wenku.baidu.com/view/364287f69e31433239689331.html?re=view
如果要理解递归,从递归的(过程式)实现而非数学原理来理解,会更加容易。从实现上来看。此外可以对照数学归纳法。
- 先想你的函数什么时候达成最优解,写出终止条件
- 然后想一个不好的解如何变得稍微接近最优解一点,写出递归
- 如果还不清楚的话复习一下数学归纳法
递归,简单点就是快速找到终止条件,然后由终止条件倒过来推运行过程
递归算法解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。
在调用的时候将现有的环境、变量参数压入栈,然后调用函数本身
函数退出的时候,从栈顶取出压入的环境、变量参数,然后完成上一个函数的调用。直到栈为空,函数停
系统根本就不管你是不是递归函数,他也不可能知道. 他只是在有函数调用的时候,把"主程序"的信息压入栈,然后调用函数,执行完后再把"主程序"的信息从
栈里弹出来,恢复. 也就是说,递归其实是一种函数调用的"技巧",只不过这种技巧很基本罢了.
当执行到fun时,发生调用,特别的是这里是调用它本身。在函数的调用处理中,不同的语言会有
不同的处理方式,这一点在编译原理的课程中讲到的比较多,分配策略有:静态分配,栈式分配,堆式分
配三种。
在过程执行时,系统使用的一个连续存储块,称为活动记录。我现就C语言的调用特点说一下活动
记录。在C语言中,当发生函数调用时,就产生了一个过程的新的活动记录,这些信息被压入栈中保存,
以便此函数执行完毕时返回时用。当函数返回时,当前记录的内容有:
| 连接数据 |
| 返回地址 |
| 动态链 |
| 静态链 |
| 形式单元 |
| 局部数据 |
-------
针对一个C程序而言,其整体的栈分配方式为:
| main调用的函数调用的其它函数(包括自己)的活动记录|
| main调用的函数的活动记录 |
| main的活动记录 |
| 全局数据区 |
-----------
理论上上就是压栈和出栈的过程
“给定一个小点的输入,完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门!(在调试的时候可以通过Call Stack这个窗口进行查看,这是调试中一个很有用的参考)
递归函数关注以下几个因素
·退出条件
·参数有哪些
·返回值是什么
·局部变量有哪些
·全局变量有哪些
·何时输出
·会不会导致堆栈溢出
在网上看到一篇文章提出了一个很新颖的观点,它提出递归应该是一种结构而不是所谓“递归函数”,这就是我说得在会使用、能懂懂之外的研究,一般教材中(不论是C语言还是其他什么语言)会把递归放在函数一章的最后一节,名曰“递归函数”,不能否认,实现递归的函数确实应该叫做“递归函数”,但是至于递归本身,我认为也应该是一个基于函数的结构,我们常说面向过程的编程有三种基本结构:顺序、分支、循环;我认为是不是递归可以跻身第四种结构或者说基本结构?因为实际上我们在探讨高级递归应用的时候,总会提到,用递归的程序都可以用迭代(其实也就是循环)的方式代替,而所有的循环程序也都可以改写成递归,这两者之间的转换只是一个程序设计难度、易读性以及程序执行效率的问题。
实际上递归时有弱点的,我们一般的教材上对递归的弱点往往都采取了回避的态度,我个人是不赞同大量使用递归的,因为递归程序往往缺乏易读性,而且编写困难,最重要的是,递归的致命弱点在于大量占用内存,越是复杂的递归结构占用内存越多(每次递归都要保存现场、转去执行新的函数),这在其他结构中是不会出现的,当然,递归有时候可能能够以空间换时间,这是递归存在的理由,在软件工程当中,空间复杂度和时间复杂度都是讨论算法优劣的因素。我在课上给学生的是:对于递归,初学的时候以了解为主,尽量不要去碰,等到自己有了数年的工作经验,再去自己判断遇到的问题是应该用递归还是循环为佳。
递归不是面向过程的编程,可以说一种函数式编程