递归的介绍(递归的特点及使用)



1 递归是什么

在c语言中,递归简单来说就是函数自己调用自己
递归中递就是递推的意思,归就是回归的意思,递归就是要把大事化小,把困难的问题分解成规模较小的小问题来解决。

最简单的调用函数:

#include <stdio.h>
int main()
{
	printf("hehe");
	main();
	return 0;
}

当程序运行进入main函数打印hehe后,调用main函数,再次打印hehe,一直重复这样的操作,最终我们会发现,程序会死递归,导致栈溢出(程序运行时使用的栈空间超出了为其分配的大小,导致程序异常终止)
在这里插入图片描述
举例:求n的阶乘
我们知道n的阶乘的公式:n!=n*(n-1)!
在这里插入图片描述

这个公式的思路就是把一个大的问题转换成与原问题类似的,但规模较小的问题来解决的。
例如当n=5的时候,
5!=5*(4!)=5* 4* (3!)=5* 4* 3* (2!)=5* 4* 3* 2* (1!)=5* 4* 3* 2* 1

代码如下:

#include <stdio.h>

int Fac(int n)
{
	if (n > 0)
		return Fac(n - 1) * n;
	else
		return 1;
}
int main()
{
	int n;
	scanf("%d", &n);	//n的值不易过大,否则结果会超出整形能表示的最大值
	int ret = Fac(n);
	printf("%d", ret);
	return 0;
}

我们能通过画图更直观的清楚递推和回归的过程。(求5的阶乘)
在这里插入图片描述

2 递归的两个重要的限制条件

• 递归需要一个限制条件,当程序满足限制条件的时候,递归便结束。(例如if语句进行判断)
• 每次递归调用的时候都要逐渐接近这个限制条件。(例如递归的值朝着限制条件一直增大或减小)

3 递归与迭代

在c语言中,每使用一次函数调用,都要在栈区为函数开辟一块内存空间,函数如果不返回,其空间会一直占用。也就是说,如果递归的层次太深,一直不返回,会导致浪费栈空间,也可能导致栈溢出。

我们平时看到的一些问题用递归的方式来解决思路很简单,但是在实现时会有很多问题,因此,我们可以考虑其他的方法,例如使用迭代(循环)的方法,迭代在实现一些问题的时候往往比递归的效率更高。

我们知道斐波那契数列是指这样一个数列:
1,1,2,3,5,8,13,21,34,55,89……这个数列从第3项开始 ,每一项都等于前两项之和。

题目:求斐波那契数列的第n个数。
在这里插入图片描述
在知道了斐波那契的公式后,我们很容易就会想到递归的方法。

#include <stdio.h>

int Fib(int n)
{
	if (n > 2)
		return Fib(n - 1) + Fib(n - 2);		//返回前两项之和
		//调用时n的值变小了,满足递归的第二个限制条件。
	else
		return 1;			//n=1和n=2时斐波那契数列都是1
}

int main()
{
	int n;
	scanf("%d", &n);
	int ret = Fib(n);
	printf("%d ", ret);
	return 0;
}

当我们输入大一点的数,例如50的时候,我们会发现程序会运行很长时间,然后给出一个错误答案,这是为什么呢?
在这里插入图片描述

在这里插入图片描述
通过画图我们可以发现,当输入一个较大的数时,越小的数被计算的次数越多。

我们可以尝试统计斐波那契前面的数被计算的次数。

#include <stdio.h>

int count = 0;
int Fib(int n)
{
	if (n == 4)
		count++;
	if (n > 2)
		return Fib(n - 1) + Fib(n - 2);
	else
		return 1;
}

int main()
{
	int n;
	scanf("%d", &n);
	int ret = Fib(n);
	printf("ret = %d ", ret);
	printf("count = %d ", count);
	return 0;
}

可以发现,当输入的数为50时,第三个斐波那契数被计算了很多次(太大了,超出int的最大范围),这会导致计算冗余,代码效率十分的低下。
在这里插入图片描述

因此我们可以考虑用迭代来实现求第n个斐波那契数。
在这里插入图片描述
1.因为斐波那契数前两个值就是1,不是相加得到的,我们可以定义变量a和b来存放1.
2.从第三个数开始,遵循每一个数等于前两个数之和的规律,所以我们可以定义变量c来保存前两个数之和的结果。
3.当每往后求一个斐波那契数,我们可以把a,b,c的位置都往后移一个位置,此时a的值为之前b的值,b的值为之前c的值。

代码如下:

#include <stdio.h>

int Fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;		//因为当n小于2时不进入while循环,直接返回c的值
	//前两个数都为1,所以可以把c的初始值赋值为1.
	while (n>2)		//只有当n>2时,满足规律
	{
		c = a + b;
		a = b;
		b = c;
		n--;//可以把n理解为次数,每次把a,b,c往后移一位后,移位的次数要减少。
	}
	return c;
}

int main()
{
	int n;
	scanf("%d", &n);
	int c = Fib(n);
	printf("c = %d ", c);
	return 0;
}

虽然程序的结果依然是错的(超出了整形能表示的最大值),但是程序一下子就出结果了,程序效率高了很多。

递归和迭代都有适用的题目,在解决比较困难的问题时,我们可以先尝试用迭代来解决,如果题目过于复杂,迭代无法解决,可以再考虑使用递归。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值