目录
一、递归的理解
递归是一种解决问题的方法,在C语言中,递归就是函数自己调用自己。
附:程序员问答社区 https://stackoverflow.com/
二、递归的思想
递归:递推/回归
把一个大型复杂问题层层转化为一个与原问题相似,但规模较小的子问题来求解;直到子问题不能再被拆分,递归就结束了。所以递归的思考就是把大事化小的过程。
三、递归的限制条件
⚪ 递归存在限制条件,当满足这个限制条件的时候,递归便不再继续。
⚪ 每次递归调用之后越来越接近这个限制条件。
四、递归的举例
① 题目:计算n的阶乘
参考:
分析:
由此我们可以得出,n的阶乘的递归公式如下:
代码实现:
画图演示:
② 题目:顺序打印一个整数的每一位
参考:
分析:
代码实现:
画图演示:
五、递归和迭代
递归是一种很好的编程技巧,但同时也可能会被误用,诸如举例①,看到推导公式,很容易写成递归的形式:
Fact函数是可以产生正确的结果,但是在递归函数调用的过程中涉及一些运行时的开销。
在C语言中每⼀次函数调用,都要需要为本次函数调用在栈区申请⼀块内存空间来保存函数调用期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就⼀直被占用,所以如果函数调用中存在递归调用的话,每⼀次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题。
因此如果不想使用递归,通常就是迭代的方式(一般就是循环的方式)。
举例 ①:计算n的阶乘
分析:事实上,我们看到很多问题是以递归的形式进行解释的,这是因为它比非递归的形式更加清晰,但是这些问题的迭代实现往往比递归实现效率更高。当一个问题非常复杂,难以使用迭代的方式实现时,递归实现的简洁性便可以补偿它带来的运行时开销。
举例 ②:求第n个斐波那契数
极端例子,该问题是不适合使用递归求解,但是却能通过递归的形式描述。那如果我们试用递归的方式实现呢?
画图演示:
观察:在计算第30个斐波那契数,使用递归方式,第8个斐波那契数就被重复计算了1047974324次,这些计算是非常冗余的。所以斐波那契数的计算,不适合用递归实现,因此我们选择迭代。
分析:
代码实现: