递归的概念
在C语言中,函数自己调用自己就是函数递归
递归的思想是把复杂的问题简单化,不断拆分成子问题来解决,直到子问题不能再进行拆分,递归结束。就是一层一层剥洋葱,大事化小事的过程
递是递推,归是回归
递归是需要前提条件的:
递归存在限制条件时,当满足了这个限制条件,递归就停止了
每次递归调用函数之后,会越来越接近这个限制条件
递归的举例
阶乘的计算
4! = 4*3*2*1
3! = 3*2*1
2! = 2*1
1! = 1
规定0! = 1
这就是阶乘的基本规律
我们仔细观察可以总结出一个公式
n! = n*(n - 1)!
我们可以照着这个公式写一个阶乘的函数Fact
int fact(int n)
{
if(n == 0)
return 0;
else
return n * Fact(n - 1);
}
我们这时候就用到了递归,将n!化为n*(n - 1)!
而此时(n - 1)!我们又未知,继续拆分化小,直到 0!为止
此时代码就很很好写了
# include <stdio.h>
int Fact(int n)//创建实现阶乘的函数
{
if (n == 0)
return 1;
else
return n * Fact(n - 1);
}
int main()
{
printf("请输入一个整数来计算他的阶乘\n");
int i = 0;
scanf("%d", &i);
Fact(i);//调用函数
int fact = Fact(i);
printf("%d\n", fact);
return 0;
}
我们用一幅图来解
顺序打印一个整数的每一位
再举个例子,前面我们倒序打印过,这次顺序用递归如何实现?
先看个例子:123
怎么得到3?———— > 123%10 == 3
怎么得到12?————>123 / 10 == 12
按照这个顺序下去,我们就能得到3 2 1
就按照这个思路,设计一个函数Print来打印n的每一位,将函数拆分再拆分
void Print(int n)//此函数不需要返回类型
{
if(n > 9)
{
Print(n / 10);
}
printf("%d ", n % 10);
}
还是以123举例,打印123就可以分为两步
第一步:Print(123 / 10)//打印12
第二步:printf(123 % 10)//打印3
Print(123)
====> Print(123) +printf(3)
====> Print(12) +printf(2)
====> print(1)
#include <stdio.h>
void Print(int n)
{
if (n > 9)
{
Print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int i = 0;
printf("请输入一个整数\n");
scanf("%d", &i);
Print(i);
return 0;
}
运行结果
递归和迭代
有些时候,我们使用递归会使重复运算次数大大增加,效率降低
比如打印第n个斐波那契数
我们定义一个Fib函数
则由公式很容易写出递归代码
int Fib(int n)
{
if(n <= 2)
return 1;
else
return Fib(n - 2) + Fib(n - 1);
}
#include <stdio.h>
int Fib(int n)
{
if (n <= 2)
return 1;
else
return Fib(n - 2) + Fib(n - 1);
}
int main()
{
int i = 0;
scanf("%d", &i);
int fact = Fib(i);
printf("%d\n", fact);
return 0;
}
我们可以看到如果数据过大,运算效率大大降低,CPU占用很大
我们来看一看第三个斐波那契数一共被算了几次
int count = 0;
int Fib(int n)
{
if (n == 3)
count++;
if (n <= 2)
return 1;
else
return Fib(n - 2) + Fib(n - 1);
}
int main()
{
int i = 0;
scanf("%d", &i);
int fact = Fib(i);
printf("%d\n", fact);
printf("count = %d\n", count);
return 0;
}
这个重复计算次数非常多,我们就按照斐波那契数的定义去写代码呢?
#include <stdio.h>
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 i = 0;
scanf("%d", &i);
int fact =Fib(i);
printf("%d\n", fact);
}
所以对于递归和迭代,我们在写代码时需要注意:
如果代码合理,能用递归就可以用递归,用少量代码即可实现大量运算
如果代码存在缺陷,此时就需要迭代了