【掌握递归】函数递归思想的形成及其应用

目录

一、递归的概念及其思想

(一)递归是什么

(二)递归的思想

(三)递归的限制条件

二、递归举例

(一)求n的阶乘

(二)顺序打印一个整数的每一位

三、递归与迭代

(一)递归

(二)迭代

结语


🔥个人主页:艾莉丝努力练剑

🍓专栏传送门:《C语言》

🍉学习方向:C/C++方向 

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平


前言:前面几篇文章介绍了c语言的一些知识,包括循环、数组、函数、VS实用调试技巧等,在这篇文章中,我将介绍函数递归的一些重要知识点! 



一、递归的概念及其思想

(一)递归是什么

递归其实是一种解决问题的方法,在C语言中,递归就是函数自己调用自己

我们写一个史上最简单的C语言递归程序代码,只不过下面的递归只是为了演示递归的基本形式,不是为了解决问题,代码最终也会陷入死递归,导致栈溢出(Stack overflow)。因此仅作展示:

#include <stdio.h>

int main()
{
  printf("hehe\n");
  main();
  //main函数中⼜调⽤了main函数 
  return 0;
}

会报出下面的警告:

(二)递归的思想

把一个大型复杂问题层层转化为一个与原问题相似,但规模较小的子问题来求解;直到子问题不能再被拆分,递归就结束了。所以递归的思考方式就是把大事化小的过程。说到这里,博主联想到了枫桥经验,和递归思想有异曲同工之妙!只不过枫桥经验是“发动和依靠群众,坚持矛盾不上交,就地解决,实现捕人少,治安好”的基层社会治理经验,大事化小小事化了啦。好啦,言归正传:递归中的递就是递推的意思,归就是回归的意思,结合知识点,友友们可以体会一下!

(三)递归的限制条件

递归在书写的时候,有两个必要条件:

(1)递归存在限制条件,当满足这个限制条件的时候,递归便不再继续;

(2)每次递归调用之后越来越接近这个限制条件。

二、递归举例

这里咱们举两个实例:一个是求n的阶乘,另一个就是顺序打印一个整数的每一位。

(一)求n的阶乘

咱们先分析出来n的阶乘的公式:n!=  n ∗ (n − 1)! 

这样咱们已经可以写出n的阶乘的递归公式了:

代码展现: 

#define  _CRT_SECURE_NO_WARNINGS 1

int Fact(int n)
{
	if (n == 0)
		return 1;
	else

		return n * Fact(n - 1);
}
//测试
#include <stdio.h>

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

咱们测试一下,看看代码有没有按照我们的想法走,这里我们输入一个4,按理说4的阶乘是24,这里应该输出24,咱们来看看是不是这样:

画图推演一下: 

(二)顺序打印一个整数的每一位

我们发现其实一个数字的最低位是最容易得到的,通过%10就能得到,那我们假设想写一个函数Print来打印n的每一位不就可以了嘛:

Print(n)

如果n是1234,那表⽰为

Print(1234) //打印1234的每⼀位 

其中1234中的4可以通过%10得到,那么

Print(1234)就可以拆分为两步:

1. Print(1234/10) //打印123的每⼀位 

2. printf(1234%10) //打印4 

完成上述2步,那就完成了1234每⼀位的打印
那么Print(123)⼜可以拆分为Print(123/10) + printf(123%10)

并且以此类推,我们可以得到:

Print(1234)
==>Print(123) + printf(4)
==>Print(12) + printf(3)
==>Print(1) + printf(2)
==>printf(1)

代码展现: 

#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void Print(int n)
{
	if (n > 9)
	{
		Print(n / 10);
	}
	printf("%d ", n % 10);
}

int main()
{
	int m = 0;
	scanf("%d", &m);
	Print(m);
	return 0;
}

咱们这里随意输入几个数字看看效果:

咱们这里以1234为例画图推演一下: 

三、递归与迭代

要对比这两种思想,我们需要结合实际例子,这里咱们就以求第n个斐波那契数为例:

(一)递归

实话实说,递归方法是不适合用来求解像求第n个斐波那契数这样的问题的,不过,用递归的形式描述是没什么问题的,而且会比用迭代描述简单的多:

 咱们来看看用递归思想写出来的代码:

#define  _CRT_SECURE_NO_WARNINGS 1

int Fib(int n)
{
	if (n <= 2)
		return 1;
	else

		return Fib(n - 1) + Fib(n - 2);
}
//测试代码
#include <stdio.h>

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

当我们n输入为50的时候,需要很长时间才能算出结果,这个计算所花费的时间,是我们很难接受的 ,咱们用二叉数来看一下第50个斐波那契数:

二叉数看第50个斐波那契数,有大量重复。

咱们把这个数再缩小一点点,还是有大量重复,例如,这里仅仅只是计算第40位斐波那契数就重复计算了3000多万次:

(二)迭代

这里用迭代的方法去实现这个代码效率就高出很多了:

#define  _CRT_SECURE_NO_WARNINGS 1

int Fib(int n)
{
	int a = 1;
	int b = 1;
	int c = 1;
	while (n > 2)
	{
		c = a + b;
		a = b;
		b = c;
		n--;
	}
	return c;
}

我们知道斐波那契数的前2个数都为1,然后前2个数相加就是第3个数,那么我们从前往后,从小到大计算就行了。

迭代(简单理解为循环)写就好了,效率高,第50000个也是一瞬间的事,只不过结果是错的,超过了int的范围(一个整型放不下太大的数字)

关于斐波那契数问题,咱们可以再稍微拓展一下:比如青蛙跳台阶问题也是斐波那契数问题,大家可以去了解一下,这里推荐一个博主的文章了解青蛙跳台阶问题:详解青蛙跳台阶问题

结语

往期回顾:

【掌握调试技巧】VS实用调试技巧详解

掌握函数(二)嵌套使用与链式访问以及函数的声明与定义

掌握函数(一):库函数与自定义函数、形参与实参、return语句

掌握数组:一维数组、二维数组、变长数组及简单的二分查找

掌握分支循环(二):三种循环、break和continue语句、循环的嵌套以及 goto 语句

掌握分支与循环(一):if语句、三种操作符、switch语句

本篇文章就到此结束了,本文为友友们分享了一些函数递归的一些重要知识点,如果友友们有补充的话欢迎在评论区留言交流!下一期我们将介绍操作符相关的一些重要知识点,感谢友友们的关注与支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值