函数的递归调用是指一个函数直接或间接地调用它自己,这种函数称为递归函数。
递归的思想:把⼀个大型复杂问题层层转化为⼀个与原问题相似,但规模较小的子问题来求解;直到子问题不能再被拆分,递归就结束了。
递归在书写的时候,有2个必要条件:
(1)递归存在限制条件,当满足这个限制条件的时候,递归便不再继续。
(2)每次递归调用之后越来越接近这个限制条件。
分析:当n>1时,n*(n-1)!;当n=1时,n!=1(此外递归结束的条件)
代码:
#include
int Fac(int n)
{
if (n <= 0)
return 1;
else
return n * Fac(n - 1);
}
int main()
{
int n = 0;
scanf("%d", &n);
int result = Fac(n);
printf("%d\n", result);
return 0;
}
运行结果:
5
120
分析:如果n是⼀位数,n的每⼀位就是n自己;如果n是超过1位数的话,就得拆分每⼀位
Print(1234)
Print(123) + printf(4)
Print(12) + printf(3)
Print(1) + printf(2)
printf(1)
代码:
#include
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
1 2 3 4
分析:设n为人数,当n=1时,age=10(递归结束条件);当n>1时,age(n)=age(n-1)+2
代码:
#include
int fac(int n)
{
int age;
if (n == 1)
{
age = 10;
}
else
{
age = fac(n - 1) + 2;
}
return age;
}
int main()
{
int m;
scanf("%d", &m);
printf("%d", fac(m));
}
运行结果:
1
10
5
18
(1)条件:递归调用的过程是首先回推,直到递归结束条件成立为止,然后再逐层递推。因此,递归结束条件必不可少。
(2)缺点:内存占用多,效率较低。
(3)优点:直观,符合人类思维习惯。
#include
int main()
{
printf("hehe\n");
main();//main函数中⼜调⽤了main函数
return 0;
}
函数的运行结果最终会陷入死循环,导致栈溢出(Stack overflow)。
(1)在C语言中每⼀次函数调用,都要需要为本次函数调用在栈区申请⼀块内存空间来保存函数调⽤期间的各种局部变量的值,这块空间被称为运行时堆栈,或者函数栈帧。
(2)函数不返回,函数对应的栈帧空间就⼀直占用,所以如果函数调用中存在递归调用的话,每⼀次递归
(3)函数调⽤都会开辟属于自己的栈帧空间,直到函数递归不再继续,开始回归,才逐层释放栈帧空间。
(4)所以如果采⽤函数递归的方式完成代码,递归层次太深,就会浪费太多的栈帧空间,也可能引起栈溢出(stack overflow)的问题。
所以如果不想使用递归就得想其他的办法,通常就是迭代的方式(通常就是循环的方式)。
就像题目1计算n的阶乘,也是可以产⽣1~n的数字累计乘在⼀起的,代码如下:
int Fac(int n)
{
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret *= i;
}
return ret;
}
迭代的效率高于递归方法,但是不如递归方式直观。
分析:当n<=2时,Fib(n)=1;当n>2,Fib(n-1)+Fib(n-2)
用递归方式的代码:
#include
int Fib(int n)
{
if (n <= 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
当我们让n=50时,会占用十分长的计算时间,而此时我们就应改成迭代的方式。
用迭代方式的代码:
#include
int Fib(int n)
{
int a = 1, b = 1, c = 1;
while (n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
而用迭代的方式我们可以看出计算的效率是十分高效的,由此我们可以知道递归方式虽然很好用,但也是有相应的缺点,而我们在编程过程中应该具体问题具体分析,不能只贪恋于单一方法。