一、什麼是遞歸?
遞歸的本質就是函數的自我調用,就是自己調用自己。
衆所周知,遞歸是一種解決問題強有力的技巧。在描述有些問題時有不可替代的優勢,但濫用遞歸很可能造成資源的巨大開銷!
二、遞歸函數調用涉及哪些運行時開銷?
<1>、參數必須壓到堆棧
<2>、函數內部定義的局部變量的值也要壓棧保存
<3>、函數的執行狀態(寄存器的值)也要壓棧保存
當遞歸函數的每次調用返回時,上述這些操作都必須還原,恢復成原來的樣子。
三、通過求斐波那契數問題來觀察遞歸的另一種開銷--大量的冗餘操作。
源代碼實現(包括遞歸形式和迭代形式):
#include <stdio.h>
static int count = 0;
/*
**函數功能: 遞歸法求第n個斐波那契數
**參數說明: @n : 斐波那契數的序號
**返回值: 第n個斐波那契數
*/
long Recursion_fibonacci(int n)
{
if (n <= 2)
{
return 1;
}
//統計計算Fibonacci(3)的冗餘次數
if (n == 3)
{
count++;
}
return Recursion_fibonacci(n - 1) + Recursion_fibonacci(n - 2);
}
/*
**函數功能: 迭代法求第n個斐波那契數
**參數說明: @n : 斐波那契數的序號
**返回值: 第n個斐波那契數
*/
long Loop_fibonacci(int n)
{
//保存三個相鄰的斐波那契數
long first_fib;
long second_fib;
long third_fib;
first_fib = second_fib = 1; //前兩個斐波那契數都是 1
third_fib = first_fib + second_fib;
while (n > 2)
{
first_fib = second_fib;
second_fib = third_fib;
third_fib = first_fib + second_fib;
n--;
}
return second_fib;
}
int main(void)
{
int n;
while (1)
{
scanf("%d", &n);
getchar();
printf("第 %d 個斐波那契數是 %d \n", n, Recursion_fibonacci(n));
printf("遞歸計算Fibonacci(3) %d 次\n", count);
printf("第 %d 個斐波那契數是 %d \n\n", n, Loop_fibonacci(n));
}
return 0;
}
運行截圖:
四、怎麼消除這種恐怖的開銷呢?
當然是變遞歸爲循環咯!上面的迭代法求斐波那契數效率可比遞歸法高了了幾十萬倍呢!所以能用迭代法替代的遞歸,就用迭代替代遞歸吧!