递归是一种数学上分而治之的思想
递归需要有边界条件
当边界条件不满足时,递归继续进行
当边界条件满足时,递归停止
递归将大型复杂问题转化为与原问题相同
递归函数:
函数体内部可以调用自己
递归函数中存在自我调用的函数
递归函数是递归的数学思想在程序设计中的应用递归函数必须有 递归出口
函数的无限递归将导致程序栈溢出而崩溃
计算字符串的长度:
int strlen_r(const char* s)
{
if( *s )
{
return 1 + strlen_r(s+1);
}
else
{
return 0;
}
}
计算1~n的和:
#include <stdio.h>
int Count(int n)
{
int sum = n;
if( n >= 1)
{
sum += Count(n-1);
return sum;
}
else
{
return 0;
}
}
斐波那契数列递归解法:
int fac( int n)
{
if ( n == 1)
{
return 1;
}
else if(n == 2)
{
return 1;
}
else
{
return fac(n-1) + fac(n-2);
}
return -1;
}
划重点:必须注意的是,递归肯定很爽,这样想着关键代码两三行就搞定了,注意这题的n是从0开始的:
if(n<=1) return n;
else return Fibonacci(n-1)+Fibonacci(n-2);
然而并没有什么用,测试用例里肯定准备着一个超大的n来让Stack Overflow,为什么会溢出?因为重复计算,而且重复的情况还很严重,举个小点的例子,n=4,看看程序怎么跑的:
由于我们的代码并没有记录Fibonacci(1)和Fibonacci(0)的结果,对于程序来说它每次递归都是未知的,因此光是n=4时f(1)就重复计算了3次之多。
Fibonacci(4) = Fibonacci(3) + Fibonacci(2);
= Fibonacci(2) + Fibonacci(1) + Fibonacci(1) + Fibonacci(0);
= Fibonacci(1) + Fibonacci(0) + Fibonacci(1) + Fibonacci(1) + Fibonacci(0);
在对时间和空间都有要求的情况下,可使用循环来进行求解:
int Fibonacci(int n)
{
int preNum=1;
int prePreNum=0;
int result=0;
if( n <= 0 )
{
return 0;
}
else if( 1 == n || 2 == n )
{
return 1;
}
else
{
for(int i=2;i<=n;i++)
{
result=preNum+prePreNum;
prePreNum=preNum;
preNum=result;
}
return result;
}
汉诺塔问题:
void han_move(int n, char a, char b, char c)
{
if( n == 1)
{
printf("%c --> %c\n", a, c);
}
else{
han_move(n-1, a, c, b);
han_move(1, a, b, c);
han_move(n-1, b, a, c);
}
}
int main()
{
char a = 'A';
char b = 'B';
char c = 'C';
han_move(3, a, b, c);
return 0;
}
小结:
递归是一种将问题分而治之的思想
用递归解决问题首先要建立递归的模型
递归解法必须要有边界条件,否则无解。