遞歸算法時間復雜度分析與改善


遞歸算法大家都不陌生,當須要反復計算同樣問題時,一般能夠選擇遞歸和循環兩種算法。

又由於遞歸實現起來代碼比較簡潔。所以通常都會使用遞歸來解決上述問題。比方斐波那契數列。再比方樹的前序、中序、興許遍歷算法。

遞歸算法盡管是有代碼簡潔這個長處,可是其缺點顯著。

由於遞歸函數是在運行過程中調用其自身,所以會占用大量的棧上空間,而且壓棧和出棧都是有時間消耗的。

所以從這一點上來看,遞歸的效率是不如循環。除了效率之外,遞歸另一個相當明顯的問題:可能會導致棧溢出。當遞歸調用的次數過大時,非常有可能會出現棧溢出的情況。

我們這里暫不考慮空間復雜度,僅討論其時間復雜度以及改善方法。

還是以經典的Fibonacci數列為例。其定義例如以下:

                               

1. 遞歸解法

對於這個題目,大家對於其算法已經十分熟悉。非常快就能寫出以下的代碼:

long long Fibonacci(unsigned int n)
{
    if (n <= 0) {
        return 0;
    }

    if (n == 1) {
        return 1;
    }

    return Fibonacci(n-1) + Fibonacci(n-2);
}
我們以f(10)為例分析來分析遞歸的計算過程。f(10)=f(9)+f(8),  f(9)=f(8)+f(7) , f(8)=f(7)+f(6)。。

。。

能夠用樹形結構來表示整個計算過程

                                   

我們能夠看出來,上面的樹中,非常多結點都是反復計算的。其實,遞歸算法的時間復雜度是n的指數級的。這種復雜度。一般來說是不可接受的。


2. 遞歸算法改善

上述的遞歸算法中。時間復雜度高的原因是過程中存在大量的反復計算。因此,假設能想辦法避免反復計算,那么其時間復雜度便能夠降下來。

比較簡單的方法是採用逆序的遞歸算法:f(0)+f(1)=f(2), f(1)+f(2)=f(3),以此類推便能夠計算出f(n)。

而且這個算法的時間復雜度非常明顯,就是O(n)。代碼例如以下:

long long Fibonacci(unsigned int n)
{
    long long fibNMinusOne = 1;
    long long fibNMinusTwo = 0;
    long long fibN = 0;
    int result[2] = {0, 1};
    int i;

    if (n < 2) {
        return result[n];
    }
    
    for (i = 2; i < n; i++) {
        fibN = fibNMinusTwo + fibNMinusOne;
        fibNMinusTwo = fibNMinusOne;
        fibNMinusOne = fibN;
    }

    return fibN;
}


免責聲明!

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



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