演算法之美 遞推之兔子的計畫生育

2021-04-20 07:47:44 字數 1923 閱讀 1512

//程式1:fibonacci數列的遞迴實現code in c/c++

int fibonacci(int n)

ok,搞定,輕鬆解決!

慢點,跑跑試一試,n=12,ok! n=40,還行。n=50,夠慢了吧!

怎麼會這麼慢呢?我們來仔細分析分析。看看這句:

return fibonacci(n-1)+fibonacci(n-2);

注意了,fibonacci(n-1) 這個遞迴呼叫其實將會產生:fibonacci(n-2)+fibonacci(n-3) (當然n大於3的時候)。看出問題了吧,對於上面這個fibonacci(n-1)+fibonacci(n-2),其實在展開之後我們呼叫了兩次fibonacci(n-2),也就是說我們重複計算了兩次f(n-2),這還僅僅是第一次的情況,隨著計算的深入,我們還會重複計算更多,請看下圖:

現在清楚了,對於f(5),僅僅是f(1)我們就多計算了4次。其實我們只需要自底向上計算f(1)到f(4)就行了。然而遞迴的時候卻自頂向下作了大量的重複計算,當然慢了!

現在清楚了問題之後,我們再來換種方法,在計算過程中將已經計算過的f(n)儲存起來,下次就不用重複計算了,看下面程式。

//程式2:自底向上求fibonacci數列 code in c/c++

int f[1000] = ;

int fibonacci(int n)}

好,現在再來算,快多了吧!其實就是個動態規劃的思想,用空間換時間。

行了,ok! 給我來個f(999)!

。。。果然夠快。。。但是。。。結果卻是錯的,負值都出來了。

當然會錯了,乙個int最多也就32位(看作業系統),那麼換成long long,64位,暫時夠用了,但是怎麼輸出任意大的f(n)呢,這個。。。咱們留到以後專題討論「大數」,先做個預告,打打廣告。

排除溢位的問題,上面的程式還有什麼問題嗎?

。。。當然有,想一想哈,假設現在我們現在解決了溢位的問題,那麼當第一次呼叫這個函式時輸入乙個很大的n時會出現什麼情況呢?

注意,現在是第一次呼叫,也就是說我們的快取陣列f[n]裡面是空的,這個時候函式會出現多少次遞迴呼叫呢?(n-1)-2次! 也就是說n-3次,當n很大時,這個開銷還是不小的。

為什麼呢?因為函式的呼叫時有開銷的。當乙個函式呼叫時,需要將函式引數入棧,並且儲存當前程式上下文資訊(也就是儲存呼叫點的位址等等),還有引數傳遞的開銷(傳遞乙個int開銷不大,那如果不幸需要傳遞並拷貝乙個類,當然你可以將類的引用傳遞進去)當n很大時,這個開銷其實是可以避免的。

怎麼避免呢?看看下面的程式

/*********************

* 程式3:遞迴和迭代

**********************/

//遞迴版計算n的階乘

long factorial(int n)

else

}//迭代版計算n的階乘

long factorial(int n)

return fac;

} 上面的程式告訴我們,遞迴的優美是有代價的~~~

好了,現在我們在回頭看看我們的兔子,將我們的程式也換成迭代版的試一試:

//程式4:迭代版fibonacci數列 code in c/c++

int f[1000] = ;

int fibonacci(int n)}

好了到此為止,兔子們的計畫生育貌似解決了(其實還是在生-_||)。

不過。。。程式裡面其實還有很多問題,比如要是n超過1000怎麼辦,等等等等,這裡我們僅僅談談解決的思路,就不深入這麼多了,留到以後再講。

ok,從零開始學演算法,邁出第一步了,謝謝!!!

設計模式之單例模式(有些類也需要計畫生育)

概念 保證乙個類只有乙個例項化物件,並提供乙個訪問它的全域性訪問點。優點 1.嚴格控制客戶怎麼訪問,如何訪問,對唯一例項受控訪問。2.在記憶體裡只有乙個例項,減少了記憶體的開銷,尤其是頻繁的建立和銷毀例項,避免對資源的多重占用。缺點 1.沒有介面,不能繼承,與單一職責原則衝突,乙個類應該只關心內部邏...

演算法之美 遞推之不犯錯不難,難的是全錯

從零開始學演算法。眼下又是開學的季節,回首當年風流往事,唏噓不已啊 吾曾經將一套英語卷子的單選題做錯14道。一共才15道題啊!難道之大,水準之高,我不由得對自己公升起一股敬佩之情。外加感動 各位看官英語都這麼好,要做個全對也不是難事,像我這種接近全錯的怕是少有古人與來者了。何以見得?不妨再算我狠一點...

數學之美介紹的 公開金鑰演算法

coding utf 8 author qinwenchao 公開金鑰的原理其實很簡單,我們以給上面的單詞 caesar 加解密來說明它的原理。我們先把它變成一組數,比如它的 ascii x 099097101115097114 每三位代表乙個字母 做明碼。現在我們來設計乙個密碼系統,對這個明碼加密...