1.递归——函数的“套娃”操作
在C语言中,允许函数自己调用自己,这种调用的过程叫做函数的递归。
但是,并不是所用的函数都能实现递归操作,若递归无终止的递归条件,那递归将无限进行下去,造成栈溢出。例如下面简单的递归代码:
int fuc1(int i)
{
return fuc1(i+1);
}
这个代码并不能跑过去,因为并没有结束的条件,栈溢出。
因此,“套娃”操作的不是无脑套娃,递归的存在有着实际的价值,能解决许多实际的问题。
递归的思想:把大事化小,层层递推拆分,直到子问题不能再拆分,再往回归求解。。
2.递归的基本原理
我们通过简单的阶乘原理进行引入:
我们知道
n
!
=
n
∗
(
n
−
1
)
∗
(
n
−
2
)
∗
.
.
.
.
.
∗
1
\begin{array}{cc} n!=n*(n-1)*(n-2)*.....*1 \end{array}
n!=n∗(n−1)∗(n−2)∗.....∗1
这个问题可以进行拆分
n
!
=
n
∗
(
n
−
1
)
!
(
n
−
1
)
!
=
(
n
−
1
)
∗
(
n
−
2
)
!
.
.
.
.
.
.
\begin{array}{cc} n!=n*(n-1)! \\ (n-1)!=(n-1)*(n-2)!\\...... \end{array}
n!=n∗(n−1)!(n−1)!=(n−1)∗(n−2)!......
每个阶乘可以拆分成比他小的另一个阶乘与它本身相乘。当拆分至“1”时,返回1。
F
(
n
)
=
{
n
!
=
n
∗
(
n
−
1
)
!
n
>
=
1
1
n
<
1
F(n)=\begin{cases} n!=n*(n-1)! &n>=1 \\ \\ 1&n<1 \end{cases}
F(n)=⎩⎪⎨⎪⎧n!=n∗(n−1)!1n>=1n<1
代码如下:
int func(int n)
{
if(n>=1)
return n*func(n-1);
if(n<1)
return 1;
}
如下列简图,清晰表明了递归的流程,递归的递推与回归是分别进行的并不是同步进行的。
3.递归的运用举例
斐波那契数列
斐波那契数列就是经典的递归案例,又称黄金分割数列。它的形式如下
F
(
n
)
=
{
F
(
n
−
1
)
+
F
(
n
+
2
)
n
>
=
3
1
n
<
3
F(n)=\begin{cases} F(n-1)+F(n+2)&n>=3 \\ 1&n<3 \end{cases}
F(n)={F(n−1)+F(n+2)1n>=3n<3
代码如下:
int Func(int n)
{
if(n<3)
return 1;
if(n>=3)
return Func(n-1)+Func(n-2);
}
但是此代码当n至足够大时,我们会发现此代码的运行速率是极其低下的,这是由于其时间复杂度为指数型增长,其实随着递归的不断展开,计算时间随之爆发性延长。
因此在日常写代码时我们一定要根据实际情况选择合适的方法,不能盲目使用递归结题。