遞歸是一種數學上分而治之的思想
遞歸需要有邊界條件
當邊界條件不滿足時,遞歸繼續進行
當邊界條件滿足時,遞歸停止
遞歸將大型複雜問題轉化爲與原問題相同
遞歸函數:
函數體內部可以調用自己
遞歸函數中存在自我調用的函數
遞歸函數是遞歸的數學思想在程序設計中的應用遞歸函數必須有遞歸出口
函數的無限遞歸將導致程序棧溢出而崩潰
計算字符串的長度:
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;
}
小結: 遞歸是一種將問題分而治之的思想
用遞歸解決問題首先要建立遞歸的模型
遞歸解法必須要有邊界條件,否則無解。