C語言基礎 遞迴的用法及示例
---------------start reading----------------
前言 遞迴在數學證明中經常使用,其意就是不停的套用同一模板逐漸歸納出最後的結果,用通俗的話來說就是自己呼叫自己。
遞迴呼叫需要注意三個問題
- 縮小問題規模
- 邊界條件
- 返回段
我們來看看遞迴的入門題 有五個人年齡不等 第五個人說,我比第四個人大兩歲; 第四個人說,我比第三個人大兩歲; 第三個人說,我比第二個人大兩歲; 第二個人說,我比第一個人大兩歲;
在以前我們可以用迴圈來實現,功能程式碼如下
int Age1(int n)//O(n),O(1) { int age = 10; for(int i=1;i<n;i++) { age += 2; } return age; }
現在我們來用遞迴實現,功能函式如下
int Age(int n)//O(n),O(n)
{
int tmp;
if(n == 1)
tmp = 10;
else
tmp = Age(n-1) + 2;
return tmp;
}
遞迴實現的思路其實是這樣的 想要知道第五個人的年齡,就要先知道第四個人的年齡; 想要知道第四個人的年齡,就要先知道第三個人的年齡; 想要知道第三個人的年齡,就要先知道第二個人的年齡; 想要知道第二個人的年齡,就要先知道第一個人的年齡。 知道了第一個人的年齡就可以算出第二個人的年齡,進而算出第三個,第四個,最終得到第五個人的年齡
實現的物理模型如圖
遞迴就是通過不停的壓棧再出棧來實現問題規模縮小。有時候遞迴很方便,但是,遞迴也有很大的缺點,下面就讓遞迴和迴圈進行一下比較,你就知道遞迴的弊處了
如上題所示程式碼 迴圈 時間複雜度:O(n)
空間複雜度:定義了變數age,i,O(2)
遞迴 時間複雜度:O(n)
空間複雜度:由於遞迴沒有找到值就不會返回,所以遞迴進行時會不停的壓棧,空間複雜度為O(n),空間使用率小
綜上所述 遞迴雖然同迴圈的時間複雜度一樣,但在空間利用率上卻大大的跟不上。在windos中棧的空間只有1M,一個字元=兩個位元組如果資料稍微一大便會使程式崩潰。
接下來讓我們來用遞迴寫一寫斐波那契數列的功能函式
int Fibno(int n) { if(n==1 || n==2) return 1; else return Fibno(n-1)+Fibno(n-2); }
經過除錯,資料上40就很難調試出來,因為他用了很大的空間
但是也有適合使用遞迴的例子 漢諾塔問題,如何用最少的次數將三個圓環一道另一根柱子上且保持順序不變
int g_count = 0;
void Move(char x,char y)
{
g_count++;
printf("%c->%c\n",x,y);
}
void Hanoi(int n,char a,char b,char c)
{
if(n == 1)
{
Move(a,c);
}
else
{
Hanoi(n-1,a,c,b);//
Move(a,c);
Hanoi(n-1,b,a,c);
}
}
int main()
{
Hanoi(5,'A','B','C');
printf("%d\n",g_count);
}
漢諾塔移動過程就可以用遞迴來實現,方便理解,而且在實際操作中也不會有太多的空間浪費,漢諾塔是最適合用遞迴的例子
---------------end---------------