斐波那契數列的遞歸實現和順序實現


今天看《劍指Offer》看到了斐波那契數列其實用遞歸調用樹的話會有很多重復計算......(之前自己就是一直圖省事,感覺寫的代碼少,用遞歸很方便,但是仔細一想的確是有很多計算是重復的,浪費了很多時間所以今天的隨筆就說一下斐波那契的順序實現吧

一、常見的遞歸實現

int Fibonacci(int num)
{
  if(num == 0 || num == 1) return num;
  return Fibonacci(num-1)+Fibonacci(num - 2)
}

以前的我一直是用遞歸寫的,因為可以看到,真的很方便(這里寫的簡單了,沒有考慮負數和異常輸入之類的,自己編寫時還是要多加考慮邊界條件和異常輸入啦~)

我們可以看出比如Num = 4時 要算Num = 3時的值 + Num = 2的值,而Num = 3時又要算一遍Num = 2的值,就很累贅。所以用順序結構從1到n這樣的話,就能少掉這個麻煩。

二、兩種順序實現

第一種方法是用兩個數不斷變換,最終得到目標值

/*順序斐波那契額*/
#include<iostream>

int Fibonacci(int n){
	int sum = 0,tmp = 0;
	int num1 = 0,num2 = 1;
	if(n == 0 || n == 1) tmp = n;
	for(int i=0;i<=n-2;i++)
	{
		tmp = num1 + num2;
		num1 = num2;
		num2 = tmp;
	}
	return tmp;
}
int main()
{
	int n;
	while(std::cin>>n)
	{
		std::cout<<"fnums is :"<<Fibonacci(n)<<"\n";
	}	
	return 0;
}

這一個方法還可以用來尋找一組數的最大值和次大值,也是循環一遍的O(n)還是很方便的。

第二種是使用隊列實現

#include<iostream>
#include<queue>

int Fibonacci(int n)
{
	if(n==0 || n==1)
		return n;
	std::queue<int> q;
	q.push(0);
	q.push(1);
	while(!q.empty() && n >= 2)
	{
		int x = q.front();
		q.pop();
		int y = q.front();
		q.push(x+y);
		n--;
	}
	q.pop();
	int result = q.front();
	q.pop();
	return result;
}

int main()
{
	int n;
	while(std::cin>>n)
	{
		std::cout<<"fnums is :"<<Fibonacci(n)<<"\n";
	}
	
	return 0;
}

當然還有一種方法是數組實現啦~我覺得用的空間會大於第一種方式,而且原理也並沒什么差別在此就不寫啦~

總之呢,遞歸雖然代碼量少,(可是代碼量少並不是決定一個程序員的強弱啊喂!)但是重復計算過程有點點多,然后可憐的棧也會出現STACK OVERFLOW(棧溢出)的錯誤,所以還是順序比較好嘛~隨着n的增大,順序的優勢也會更加明顯的~


在《劍指Offer》上還說了需要知識遷移的能力,提到了一只青蛙一次可以跳上1級台階,也可以跳上兩級台階,問青蛙跳上n級台階總共有幾種跳法的問題.

這類問題可以這樣想,1級台階有1種,2級台階有兩種,我們可以知道上3級台階前,青蛙一定是站在n-2(1)級台階或者上n-1(2)級台階,所以就是把F(n-2)+F(n-1)加在一起就是上n級台階的跳法總數啦,沒錯,就是你!斐波那契數列!

和這個思維很像的還有漢諾塔問題,要把柱子A的N個圓盤放到C,也就是把柱子A的N-1個圓盤放到B,然后再把第N個圓盤放在C,最后把B柱子通過A放到C,也就是2*F(N-1)+1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM