通過求斐波那契數理解遞歸的恐怖開銷!

一、什麼是遞歸?

       遞歸的本質就是函數的自我調用,就是自己調用自己。

       衆所周知,遞歸是一種解決問題強有力的技巧。在描述有些問題時有不可替代的優勢,但濫用遞歸很可能造成資源的巨大開銷!


二、遞歸函數調用涉及哪些運行時開銷?

       <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;
}


運行截圖:


四、怎麼消除這種恐怖的開銷呢?

       當然是變遞歸爲循環咯!上面的迭代法求斐波那契數效率可比遞歸法高了了幾十萬倍呢!所以能用迭代法替代的遞歸,就用迭代替代遞歸吧!



發佈了51 篇原創文章 · 獲贊 55 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章