本文介绍: 这次博客内容是与递归有关,递归学习C语⾔函数绕不开的⼀个话题,那什么递归呢?接下来正⽂开始。递归其实是一种解决问题方法,在C语言中,递归就是函数自己调用自己。来看看一个简单的C语言递归代码int main()main();//main函数中⼜调⽤了main函数return 0;上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演示递归的基本形式,不是为了解决问题,代码最终也会陷⼊死递归,导致栈溢出。把⼀个大型复杂问题层层转化为⼀个与原问题相似,但规模较小的子问题求解

1.前言

这次博客内容是与递归有关,递归是学习C语⾔函数绕不开的⼀个话题,那什么是递归呢?接下来正⽂开始。

2. 递归的定义

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

看看一个简单的C语言递归代码

#include <stdio.h>
int main()
{
 printf("hehen");
 main();//main数中⼜调⽤了main函数
 return 0;
}

上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演示递归的基本形式,不是为了解决问题,代码最终也会陷⼊死递归,导致栈溢出
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

递归的思想
把⼀个大型复杂问题层层转化为⼀个与原问题相似,但规模较小的子问题求解;直到子问题不能再被拆分,递归就结束了。所以递归的思考方式就是大事化小过程
递归中的就是递推的意思,就是回归的意思,接下来慢慢来体会。

3. 递归的限制条件

递归在书写时候,有2个必要条件

  1. 递归存在限制条件,当满足这个限制条件时候,递归便不再继续。
  2. 每次递归调用之后越来越接近这个限制条件
    在下面的例子中,我们体会一下这2个限制条件。

4. 递归举例

4.1 求n阶乘

计算n阶乘(不考虑溢出),n阶乘就是1~n的数字累积相乘。

4.1.1 分析和代码实现

在这里插入图片描述
将5的阶乘分成4的阶乘乘5;
将4的阶乘分成3的阶乘乘4;
将3的阶乘分成2的阶乘乘3;
将2的阶乘分成1的阶乘乘2;
在这里插入图片描述
这样的思路就是把⼀个较大的问题转换为⼀个与原问题相似,但规模较小的问题求解的。直到n是1或者0时,不再拆解
最终将n的阶乘就写成n*(n-1)!
直到n是1或者0时,不再拆解
在这里插入图片描述
如果将阶乘写成一个函数Fact(n),
那么Fact(n)=n*Fact(n-1)

再稍微分析一下,当 n<=1 的时候,n的阶乘是1,其余n的阶乘都是可以通过上述公式计算
n的阶乘的递归公式如下
在这里插入图片描述
我们就可以写出函数Fact求n的阶乘,假设Fact(n)就是求n的阶乘,那么Fact(n-1)就是求n-1的阶乘,函数如下:

int Fact(int n)
{
 if(n<=0)
 return 1;
 else
 return n*Fact(n-1);
}

测试一下:

int Fact(int n)
{
 if(n<=0)
 return 1;
 else
 return n*Fact(n-1);
}

int main()
{
	int n = 0;
	scanf("%d", &amp;n);
	int ret = Fact(n);
	printf("%dn", ret);

	return 0;
}

我们知道3的阶乘就是321=6,结果显然是我们所想的。
在这里插入图片描述

4.1.2 画图演示

蓝色是递推的过程,此时并没有开始相乘。
而红色是回归过程,此时回归时相乘。
在这里插入图片描述
在这里插入图片描述

4.2 顺序打印一个整数的每一位

输⼊一个整数n,打印这个按照顺序打印整数的每⼀位

输⼊:1234 输出:1 2 3 4
输⼊:521 输出:5 2 1

4.2.1 分析和代码实现

这个题目,放在我们面前,首先想到的是,怎么得到这个数的每一位呢?
1234%10就能得到4,然后1234/10得到123,这就相当于去掉了4;
然后继续对123%10,就得到了3,再除10去掉3,以此类推;
不断的 %10 和 10 操作,直到1234的每⼀位都得到;
但是这里有个问题就是得到的数字顺序是倒着的。
但是我们有了灵感,我们发现其实个数字的最低位是最容易得到的,通过%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)

直到被打印的数字变成⼀位数时候,就不需要拆分,递归结束

那么代码就是

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

int main()
{
	int n = 0;
	scanf("%d", &amp;n);//1234
	Print(n);

	return 0;
}

在这里插入图片描述
在这个解题过程中,我们就是使用了大事化小的思路
Print(1234) 打印1234每一位,拆解为首先Print(123)打印123的每⼀位,再打印得到的4
Print(123) 打印123每一位,拆解为首先Print(12)打印12的每一位,再打印得到的3
直到Print打印的是一位数直接打印就行。
在这里插入图片描述

4.2.2 画图推演

在这里插入图片描述

4.3 求第n个斐波那契

斐波那契数列前两项都是1,后面的是前面两项的和。
在这里插入图片描述
斐波那契数的问题通过是使用递归的形式描述的公式。
在这里插入图片描述
看到这公式,很容易诱导我们将代码写成递归的形式,如下所示

int Fib(int n)
{
	if (n <= 2)
		return 1;
	else
		return Fib(n - 1) + Fib(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &amp;n);
	int ret = Fib(n);
	printf("%dn", ret);
	return 0;
}

测试一下:

在这里插入图片描述
当我们n输⼊为50的时候需要很长时间才能算出结果,这个计算花费的时间,是我们很难接受的,这也说明递归的写法是非常常低效的,那是为什么呢?
要计算50就要先计算49和48,要计算49就要计算48和47,要计算48就要计算47和46,…一直这个下去,浪费时间重复计算。
在这里插入图片描述
那么除了递归还有其它的方式吗?
此时就要介绍迭代

5. 递归与迭代

递归是一种很好的编程技巧,但是很多技巧一样,也是可能被误用的,就像举例1⼀样,看到推导的公式,很容易就被写成递归的形式:
在这里插入图片描述

int Fact(int n)
{
 if(n<=0)
 return 1;
 else
 return n*Fact(n-1);
}

Fact函数是可以产生正确结果,但是在递归函数调用过程中涉及一些运行时的开销。

在C语言中每一次函数调用,都要需要为本次函数调用在栈区申请⼀块内存空间保存函数调用期间的各种局部变量的值,这块空间称为运行堆栈,或者函数栈帧。
函数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用存在递归调用的话,每⼀次递归函数调用都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间
所以如果采用函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出stack over flow)的问题。

所以如果不想使用递归就得想其他的办法,通常就是迭代方法(通常就是循环方法)。
比如:计算n的阶乘,也是可以产生1~n的数字累计乘在⼀起的。

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

	return 0;
}

在这里插入图片描述
上述代码是能够完成任务,并且效率是比递归的方式更好的。

注意:

  1. 如果一个问题使用递归的方式去写代码,是非常方便的,简单写出的代码是没有明显缺陷的,这个时候使用递归就可以
  2. 如果使用递归写的代码, 是存在明显的缺陷
    比如: 栈溢出效率低下等
    时候必须考虑其他方式比如迭代

5.1 迭代求第n个斐波那契数

在这里插入图片描述

两个数不需要计算,假设第一个用a记录第二个用b记录。当n大于2时就要实现前面两个数字,就要相加然后将a和b都向后挪,也就是将b的值给a,c的值给b,然后执行a+b,每执行一次n都要减减一下。

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;
}

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

	return 0;
}

在这里插入图片描述
有问题请指出,大家一起进步!

原文地址:https://blog.csdn.net/zxctsclrjjjcph/article/details/134793826

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_43342.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注