函数递归是什么
递归是一种解决问题的方法,在C语言中就是函数自己调用自己。利用函数递归可以解决一些简单但是很繁琐的问题,比如经典的求斐波那契数列和青蛙跳台阶问题,在本次函数递归的学习中,我们会对这个问题进行详细的解释。
递归的思想
把一个大型复杂的问题,转化为一个与原问题相似,但规模小的子问题来求解,简单来说就是大事化小小事化了的思想。
递归:这个词就是递推和回归的意思
为了帮助更好的理解,我们下面来看一个最简单的递归
void print()
{
printf("hehe");
print();
}
int main()
{
print();
return 0;
}
看一下这个代码,这就是一个打印hehe的递归,但是这个代码不会无限循环,它会报错,原因就是因为这个递归函数没有终止条件,递归会无限制地执行下去,直到程序耗尽系统栈空间或导致系统崩溃。这种情况被称为无限递归,是一种常见的编程错误,容易导致程序崩溃。
所以,函数递归要满足下面的要求
递归程序必须有一个结束条件,并且每一次递归都更加的接近这个条件。
int i = 10;
void print()
{
printf("hehe\n");
i--;
if(i>0)
print();
}
int main()
{
print();
return 0;
}
看,上面是我们改之后的正确代码,这样设置了递归终止条件,每一次调用函数都更加的接近这个终止条件。
斐波那契数列
斐波那契数列:前两个数相加得到第三个数,前两位数组是1
1 1 2 3 5 8 13……
就是这样一个数列,假如我们现在要求该数列中第n个数是多少,要知道第n个数的大小,我们就要先知道n-1和n-2的大小,把这两个相加得到n的大小。但是要想知道n-1是多少,就要知道(n-1)-1和(n-1)-2的大小。分析这个思路,我们这里可以把这个复杂的程序分解成一个个的子问题来求解
来,我们看看如何用递归的方法实现这个代码
int Fib(int n)
{
if (n < 3)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d", ret);
return 0;
}
这是一个比较经典的函数递归代码,我们来理解一下这段代码,
令n=4,进入Fib函数,执行else中的return语句,
ret=Fib(3)+Fib(2)
Fib(3)又进入else中的return语句
Fib(2)返回if中的return语句,返回1
Fib(3)=Fib(2)+Fib(1)
Fib(2)和Fib(1)都返回1
即Fib(4)=Fib(3)+Fib(2)=Fib(2)+Fib(1)+Fib(1)
返回的ret=3
在求斐波那契数是,递归只是一种实现方法,如果你在程序中输入50来求第50位斐波那契数,该程序一时半会得不到答案,原因是什么呢
我们来更改一下这个代码,计算一下n=3时,函数调用了几次
int count = 0;
int Fib(int n)
{
if (n == 3)
count++;
if (n < 3)
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);
printf("%d", count);
return 0;
}
使用count来计算一下,我们发现计算斐波那契数列的第40个数,n=3函数调用了4千万次,可见,递归的方法求斐波那契数列效率是非常低的,它在不停的重复计算,当n=50时,他的计算量是非常大的
看,仅仅是多计算了一位,n=3调用就增加了两千万次。
从这里我们可以得出,不要过于依赖递归这种方法,它只是在某些情况下受用
对于求斐波那契数列,显然递归的方法是不合适的,我们可以使用迭代的方法,这样大大提高程序的效率
int Fib(int n)
{
long long a = 1;
long long b = 1;
long long c = 1;
while (n >= 3)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
看这段就是迭代的代码实现,大大提高了效率。
了解了函数递归,我们来看一个经典的递归题
青蛙跳台阶问题
一只青蛙跳台阶,一次只能跳一个或两个台阶,问跳n阶台阶共有多少中跳法。
有n阶台阶,第一次跳,剩下的台阶可能是n-1或者n-2,、
若是n-1,则第二次剩n-2或者n-3阶台阶
若是n-2,则第二次剩n-3或者n-4阶台阶
……
以此类推
看上面的图来帮助理解,结果是0或1则返回1就表示这是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", &n);
long long ret = Fib(n);
printf("%ld\n", ret);
return 0;
}
这里再提一下汉诺塔,这也是一个经典的递归题,感兴趣的可以去了解一下,增加一下对递归的理解
感谢观看,有错误请指出