本章讲述的是有关函数递归的内容,虽然内容很少,但是对于初学者来说递归的思想并不简单,因此希望本章内容对你有所帮助。
1.什么是递归
在学习之前,我们要先了解什么是递归,递归其实是⼀种解决问题的⽅法,在C语⾔中,递归就是函数⾃⼰调⽤⾃⼰,什么意思呢,我们来看下面这段代码。
#include <stdio.h>
int main()
{
printf("hehe\n");
main();//main函数中⼜调⽤了main函数
return 0;
}
上述就是⼀个简单的递归程序,只不过上⾯的递归只是为了演⽰递归的基本形式,不是为了解决问题,代码最终也会陷⼊死递归,我们在这里只需要直到,递归就是调用自己的过程。
1.递归的思想
了解了递归,之后我们就要明白递归的思想是什么,它有什么用,其实递归的思想就是把⼤事化⼩的过程。
递归中的递就是递推的意思,归就是回归的意思,在这里大家可能会感觉有点抽象,没关系,大家只要有个印象就行,之后我会带大家一步一步去了解。
2.递归的限制条件
递归在书写的时候,有2个必要条件:
• 递归存在限制条件,当满⾜这个限制条件的时候,递归便不再继续。
• 每次递归调⽤之后越来越接近这个限制条件。
在下⾯的例⼦中,我们来逐步体会这2个限制。
2.递归举例
1.举例1:求n的阶乘
我们首先用循环来实现这个题目
#include<stdio.h>
int main()
{
int n = 0;
int ret = 1;
scanf("%d", &n);
for (int i = n; i >0; i--)
{
ret *= i;
}
printf("%d", ret);
return 0;
}
我们可以看到循环实现很简单,那么用递归怎么去做呢?
我们知道n的阶乘的公式:
n
!
=
n
∗ (
n
− 1)!
举例:
5! = 5*4*3*2*1
5! = 5*4!
4!= 4*3!
3!= 3*2!
2!= 2*1
我们发现这就是一个逐步递推的过程,同时我们也把一个大问题转换成了一个个小问题。
我们知道,递归是有限制条件的,这个题目的限制条件就是当n==0时,
n的阶乘是1,我们直到递归是在函数中进行的,因此我们创建一个Fact(n)函数来实现阶乘的实现。
我们代码实现一下
#include <stdio.h>
int Fact(int n)
{
if (n == 0)
return 1;
else
return n * Fact(n - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fact(n);
printf("%d\n", ret);
return 0;
}
我们画图推演一下
此时就是递推的过程,那回归是怎么回的呢?
蓝色代表就是回归的过程
2.举例2:顺序打印⼀个整数的每⼀位
输⼊⼀个整数m,打印这个按照顺序打印整数的每⼀位。
⽐如:
输⼊:1234 输出:1 2 3 4
输⼊:520 输出:5 2 0
如果n是⼀位数,n的每⼀位就是n⾃⼰,n是超过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 m = 0;
scanf("%d", &m);
Print(m);
return 0;
}
同样我们画图看一下
3.结语
递归的内容很少,但是它理解起来却很难,不过它却很能锻炼编程的思维逻辑能力,我们在写代码时,如果代码能用循环实现,尽量不去用递归,因为递归的开销太大,那我们为什么要学习呢,其实,到后期有些问题必须要递归去解决,因此递归虽然理解难,又比不上循环,但是我们还是有学习的必要,最后永远都不要放弃,坚持才是胜利!