日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

优化递归的效率

發布時間:2025/3/21 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 优化递归的效率 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

函數遞歸調用是很常見的做法,但是它往往是低效的,本文探討優化遞歸效率的思路。

1.尾遞歸轉換成迭代

尾遞歸是一種簡單的遞歸,它可以用迭代來代替 比如 求階乘函數的遞歸表達

int?f(int?n)
{
????
if(n<=0)return?1;
????
return?n*f(n-1);
}

可以轉換成完全等價的循環迭代

int?f(int?n)
{
????
int?r=0;
????
while(n-->0)
????????r
*=n;
????
return?r;
}

尾遞歸是最簡單的情形,好的編譯器甚至可以自動的識別尾遞歸并把它轉換成循環迭代。

2.動態規劃

我一直把動態規劃看作尾遞歸的推廣(個人觀點),在2維或更高的情況下,直接使用遞歸會造成大量的重復計算,例如在斐波那契數列的遞歸關系 Fib(n+2)=Fib(n+1)+Fib(n)中 Fib(3)在計算Fib(4)和Fib(5)都會用到 他被重復計算了2遍,當數列長度增大時 這種浪費會變得越來越明顯。

動態規劃方法將可能需要的結果全部計算出來 并保存 一般來說 動態規劃從最小數開始 自底向上計算所有值(因為后面的結果會用到前面的結果) 直到得到的結果中包含了要求的結果。

int?Fib(unsigned?n)
{
????
if(n==1)return?1;
????
if(n==0)return?0;
????
return?Fib(n-1)+Fib(n-2);
}



int?Fib(unsigned?n)
{
????
int*?f=new?int[n+1];
????f[
1]=1;f[0]=0;
????
for(int?i=0;i<=n;i++);
????????f[i]
=f[i-1]+f[i-2];??
????
int?r=f[n];
????delete[]?f;
????
return?r;
}

動態規劃不會造成重復運算 但是 它可能計算不需要的結果 例如關系式
? ?? a(n)=a(n-2)+a(n-4);
使用動態規劃會計算很多不需要的結果,盡管如此,它的效率遠遠高于直接遞歸運算。

實際上,大部分時候動態規劃把指數級時間復雜度的遞歸運算變成了多項式級時間復雜度的遞推。

3.備忘錄

減少重復值的另一個方法是使用備忘錄,每次成功計算一個結果 ,就將它存入備忘錄中,當再次遇到此問題時,無需重復計算,直接取出即可。

備忘錄方法和直接遞歸相似,只是在函數在計算之前先訪問備忘錄,如果在備忘錄中找到,就無須再計算,直接返回。

備忘錄結構可以使用關聯數組 哈希表等實現,特別地,當遞歸參數是整數時 直接用數組就可以了。

與動態規劃相比,備忘錄消耗了額外的備忘錄查找時間,并且和直接遞歸一樣 有大量的多余函數調用開銷,但它不會造成額外計算。

4.內聯

這是來自Efficient C++的方法,C++編譯器不會把遞歸函數內聯,這樣,函數調用的開銷變得很大。為了提高效率,必須手動內聯函數。
遞歸函數無法完全內聯,但是我們可以把它展開,這是前面Fibnacci函數的一層展開

int?Fib(unsigned?n)
{
????
if(n==1)return?1;
????
if(n==0)return?0;

????
int?fn1,fn2;
????
if(n-1==1)fn1=1;
????
else?if(n-1==0)fn1=0;
????
else?fn1=Fib(n-2)+Fib(n-3);

????
if(n-2==1)fn2=1;
????
else?if(n-2==0)fn2=0;
????
else?fn2=Fib(n-3)+Fib(n-4);

????
return?fn1+fn2
}

?5.解遞歸
盡管我們傾向于虐待計算機 讓它幫我們處理較復雜的問題,但是很多時候我們需要獲得效率,就必須自己動手,其實很多遞歸式可以手動解出,組合數學為我們提供了不少工具:
???? (1)解齊次遞歸方程

簡單的遞歸方程可以按以下步驟求解:

解Fibonacci函數的遞歸方程 首先把它轉換成下面的式子 這個代數方程被稱為遞歸方程的特征方程,下一步是解特征方程求出它的所有解,對這個例子來說 根據組合數學的結論 再由 F(0)=0和F(1)=1可以得出方程組 解這個方程組可得到a和b的值 代入前面的公式可以求出Fibnacci通項公式 驗證后可以知道,這個公式是正確的,顯然用此公式做浮點運算,比使用遞歸方式快得多。 (2)母函數 組合數學中還提供了一種更強有力的處理手段:生成函數(又稱為母函數) 仍然以求解Fibonacci數列為例,為了易于理解,我這里把生成函數描述成一個以Fibonacci數列為系數的多項式。即 現在考慮這樣一個多項式 按g(x)的定義,可以這樣展開 這個時候不要忘記我們的遞推公式,可以進一步化簡為 這個式子與g(x)非常像,將它兩邊同時乘以x 再整理一下等式 利用F(0)=0,F(1)=1可以求出 這樣 我們求出了g(x),等等,g(x)是什么來著?不是以Fibonacci數列為系數的多項式么?現在求出的東西是什么?不要急,用泰勒級數展開就能得到通項公式了,結果跟上面的是一樣的。(太麻煩了,略過略過^_^)

from: http://www.cnblogs.com/winter-cn/archive/2008/08/23/1274475.html

總結

以上是生活随笔為你收集整理的优化递归的效率的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。