9.C语言函数递归,求n的阶乘(n!)(快乐动画版)

文章目录

  • 1.递归是什么
  • 2.使用递归的限制
  • 3.讨论n太大为什么会栈溢出?

1.递归是什么

函数自己调用自己。

2.使用递归的限制

2个限制条件:
每次递归调⽤之后越来越接近这个限制条件,当满足限制条件时,递归便停止。
看栗子:求n的阶乘,n! = n ∗ (n − 1)!
2个限制条件如下:
9.C语言函数递归,求n的阶乘(n!)(快乐动画版)_第1张图片
代码实现
不考虑n太大,因为会溢出(后面结尾解释为什么溢出,并且求阶乘的更好的方法是迭代不是递归)

#include 
int Ret(int n)
{
	if (n <= 0)
		return 1;
	else
		return Ret(n - 1) * n;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	
		int ret = Ret(n);
		printf("%d的阶乘是%d", n, ret);
	
	return 0;
}

运行结果:
9.C语言函数递归,求n的阶乘(n!)(快乐动画版)_第2张图片
为了更容易观察代码的变化动图里面,我将代码里面的Ret(n-1)*n的结果视觉化成num,把返回值回来时的n用 n=n 视觉化成n,这样子,可以用监视窗口观察n和num的变化

  1. 如果满足第一个限制条件,代码是怎么运行的,输入0进行调试。
    (如果不懂vs怎么调试的,可以移步我的这篇博客 http://t.csdn.cn/h8roc)
    我是直接F11进行调试,随着箭头的移动,代码在一步一步进行。9.C语言函数递归,求n的阶乘(n!)(快乐动画版)_第3张图片

  2. 如果满足第二个限制条件,代码是怎么运行的,输入0进行调试。
    为了更容易观察代码的变化把Ret(n-1)*n的结果视觉化成num,把返回值回来时的n用 n=n 视觉化成n,这样子,可以用监视窗口观察n和num的变化
    动图描述:

文字描述:
看到 n 输入1的时候,跳到 Ret(n-1)*n 那里时,函数开始调用自己,不断n-1,我们也可以看到n不断变化:1,0
然后再不断返回自己的值,比如调用到n=0时,return 1,然后跳到n=1时,num=(返回的1)乘(n=1),num=1,再return num,因为n=1是最初的n,所以num是直接返回主函数的Ret(n)。
画图描述:
9.C语言函数递归,求n的阶乘(n!)(快乐动画版)_第4张图片

这是输入2的代码递推和回归过程:
9.C语言函数递归,求n的阶乘(n!)(快乐动画版)_第5张图片

3.讨论n太大为什么会栈溢出?

每⼀次函数调⽤,都需要为本次函数调⽤在栈区申请⼀块内存空间,保存函数调⽤期间的局部变量的值,
这块空间被称为运⾏时堆栈,或者函数栈帧
假设我们的n是100
函数递归一直不返回,函数对应的栈帧空间就⼀直占⽤,直到函数递归不再继续,开始回归,才逐层释放栈帧空间,所以如果采⽤函数递归的⽅式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack over flow)的问题。
9.C语言函数递归,求n的阶乘(n!)(快乐动画版)_第6张图片
所以如果不想使⽤递归,通常我们用迭代(一般是循环的⽅式)

int main()
{
	int i = 0;
	int n = 1;
	scanf("%d",&n);
	int ret = 1;
	for (i = 1; i <= n; i++)
	{
		ret *= i;
	}
	return 0;
}

此时该问题的求解,迭代实现往往⽐递归实现效率更⾼。
所以我们要看问题选择解题方法,当⼀个问题⾮常复杂,难以使⽤迭代的⽅式实现时,此时递归实现的简洁性便可以补偿它所带来的运⾏时开销。
//下一章我们更新用递归解决的例子。
1.顺序打印⼀个整数的每⼀位
2.求第n个斐波那契数
3.编写一个函数实现n的k次方,使用递归实现
4.写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和

你可能感兴趣的:(c语言,开发语言,经验分享,笔记)