c语言:递归与迭代

递归

      递归是一个函数自己调用自己的过程。那么为什么要自己调用自己呢?当遇到一个复杂,且可以分成多个与原问题相似的问题时,我们不想用大量的代码去实现,就可以使用递归,也就是自己调用自己,每次调用自己都会比原问题更加简单,也可以说成把大事化小的过程。

    递归的本意是实现两个动作,递是递归的意思,归是回归的意思。

下面让我们看看什么是自己调用自己吧:

像图片中main函数中又调用了一个main函数就是递归的使用,当然,这段代码如果运行,会使程序陷入死循环,无限打印printf函数中要打印的内容,所以,这并不是递归的正确打开方式,递归的使用必须有使用递归无法使用得的限制条件,使程序不会陷入死循环,还必须让每次递归调用都

更接近这个限制条件,文字难以理解,接下来我们用代码实例来解释吧:

例如我们要用求一个数的阶乘,递归就可以很好的解决这个问题

int Fact(int n)
{
	if (n == 0)
		return 1;
	else
		return n * Fact(n - 1);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int r = Fact(n);
	printf("%d", r);
	return 0;
}

我们试着输入5,让它求5的阶乘

输入5,输出120,没错,5的阶乘为120,怎么样,递归的代码是不是特别简洁呢?

那么它是如何实现的呢?下面我将对它的代码一一讲解:

我们进入main函数创建了一个数n,它就是我们输入的要求阶乘的数,而求n的阶乘的功能主要是由Fact函数实现的,Fact函数内部也很简单,只有寥寥几行代码,我们要解释这几行代码首先就要我们解释我们实现求阶乘的思路,假如我们要实现一个数的阶乘,我们把求阶乘看成:

5!=5×4!

4!=4×3!

3!=3×2×1

也就是我们要求n的阶乘,可以用n乘以n-1的阶乘,这样就可以使用递归大事化小的特性,把求n的阶乘变成n×n-1!,求n-1的阶乘变成n-1×n-2!.......

现在,我们再来看Fact内部的代码

假如我们传入一个5,这个5由n接收,每次进入函数都判断n是否等于0,等于0则返回1,不等于则执行后面的代码,返回n×n-1的阶乘,而这个n-1的阶乘又是由Fact函数实现的,但是这一次传入的是n-1,下次进入函数时,参数n接收的数也是n-1,也就是4,函数会被多次调用,直至n等于0时,函数返回1,就开始回归,我们还是看图吧:

这张图充分体现了递归的递推和回归的特性。

递归的缺陷

递归有着代码简洁高效的优点,是不是意味着它在任何地方都可以使用呢?并不是,在一些看似能

使用递归的场景实则使用递归会使程序的计算量变得非常巨大。例如:我们要求第n位的斐波那契数列的值,在设计程序之前,我们先简单的了解一下斐波那契数列

斐波那契数列就是第一位为1,第二位为1,往后的每一位都由前两个数字相加所得,例如第十位的55是由第8位的21与第9位的34相加所得。由此条件,我们很快就能用递归实现:

#include<stdio.h>
int Fact(int n)
{
	if (n <= 2)
		return 1;

	return Fact(n - 1) + Fact(n - 2);
}
int main()

{
	int n = 0;
	scanf("%d", &n);
	int r = Fact(n);
	printf("%d ", r);
	return 0;

}

当我们输入10,求斐波那契数列的第10位数,果然得到了55,这样一看,还没有什么问题 ,但是当我们要求更大位数的值时:

它却没有得出结果,这是为什么呢,因为,函数在内部多次调用了自己,产生了大量的重复计算,导致计算量巨大,代码执行效率非常低,让计算机也无法快速得出结果,这个例子告诉我们,递归是有使用条件的 ,如果要设计一个需要重复计算的程序,不能无脑使用递归,而是首先要思考递归能不能用,是否能让代码简洁的同时,更加高效,那么此类例子我们如何解决呢?接下来我们要介绍另一种能多次重复相同计算的方法。

迭代

   迭代是类似循环的方法,它包含了循环,本质是多次做相同的动作,使程序运行起来实现我们要实现的功能,上述例子使用迭代能高效地解决:

#include<stdio.h>
int Fact(int n)
{
	int i = 0;
	int a = 1;
	int b = 1;
	int c = 0;
	int temp = 0;
	for (i = 1; i <= n - 2; i++)
	{
		c = a + b;
		temp = c;
		a = b;
		b = temp;
	}
	return c;
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int r = Fact(n);
	printf("%d", r);
	return 0;
}

这次我们试着求第50位的斐波那契数:

可以看到,很快就得到了结果,但是答案是错误的,因为要求的数太大,一个字节无法表示,但是我们可以很直观的看见两者的差别,在这这样一个例子中,使用迭代会优于使用递归。所以,使用递归还是迭代,需要分析二者的优点和缺点选择更适合的方法。 

  • 52
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值