第六講 經典演算法之遞迴與分治

2021-09-04 10:32:43 字數 2374 閱讀 9375

遞迴與分治,顧名思義,就是既有遞迴又有分治。遞迴指函式呼叫自身,分治是指乙個大的問題被分成了幾個小問題,分而治之。總得來說,按我的理解,就是將乙個具體的問題抽象成一類問題,在解決該具體問題時,將原問題逐個的分解成更小的問題,然後分別遞迴呼叫同乙個函式來解決。

回顧一下我們熟悉的斐波那契數列的計算:f(n

)=

1&n=1\cr 1&n=2\cr f(n-1)+f(n-2)&n>2\end

f(n)=⎩

⎪⎨⎪⎧

​11f

(n−1

)+f(

n−2)

​n=1

n=2n

>2​

c語言遞迴**如下:

int

fib(

int n)

顯然,這裡為了計算fib(n),將之分解成了計算fib(n-1)fib(n-2)並求和,這裡的引數n可以看做是問題的規模,即乙個大問題被分解成了兩個小問題,而小問題又會被分解成兩個更小的問題…… 直到遞迴函式的出口n<=2時直接返回結果1。沒錯,這其實就是乙個簡單的遞迴與分治的思想。

來對比一下for迴圈實現的版本:

int

fib(n)

return ans;

}

對比之後不難發現,遞迴函式的**十分簡練而優雅,這也是遞迴與分治思想的特點之一,**實現起來特別短小精悍!

評斷乙個演算法好不好,最直接的感受就是算得快不快。對上面兩種斐波那契數列的計算方法通過幾個輸入樣例進行測試,不難發現,隨著n越來越大,到二三十甚至更大的時候,精煉的遞迴分治演算法執行得尤為緩慢,甚至再大一點都跑不出結果了,而for迴圈實現的演算法基本都是秒出結果,這是為什麼呢?

試著分析分析兩個演算法的時間複雜度,for迴圈版本的斐波那契數列計算時間複雜度顯然就是線性時間複雜度o(n);而遞迴函式的時間複雜度並不是很直觀,其實計算過程也不難,就是推導遞迴式,有點像高中數學裡的已知遞推方程求數列的通項公式。

為了表達方便,這裡我們用t(n)表示計算乙個規模為n的問題所需的時間(此處就是計算第n項斐波那契數列所花的時間),顯然由已知條件可以知道,前兩項斐波那契數列是已知的,不需要計算,即t(1)=t(2)=0,即有遞推方程:t(n

)=

0&n<=2\cr t(n-1)+t(n-2)+1&n>=3\end

t(n)

=顯然,時間複雜度為o(n)

再考慮如下的遞迴實現版本:

int

power

(int a,

int n)

一如既往的簡練,可是時間遞推式t(n) = t(n-1)+1仍然是線性衰減,時間複雜度仍然為o(n),雖然不夠好,至少在時間複雜度不變的情況下**變高大上了。

再考慮乙個冪運算的規律:an=

a^}*a^} & n\%2=0\cr a^}*a^}*a & n\%2=1\end

an=不難分析,時間遞推式如下:t(n

)=

t(n/2)+1 & n>=2\cr 0 & n<=1\end

t(n)={

t(n/

2)+1

0​n>=2

n<=1

​不難求解出答案t(n

)=o(

log2

(n))

t(n)=o(log_2(n))

t(n)=o

(log

2​(n

))這樣一來,時間複雜度便從o(n)降成了o(logn),實現了效率的提高。

所以,其實使用遞迴與分治關鍵是你如何拆分這個問題。而且有的問題可能無論如何拆分也不能較好的通過遞迴與分治降低時間複雜度甚至還會增大時間複雜度;而有的問題可能換乙個角度思考就能利用某種規律實現問題規模成比例的下降,從而運用遞迴與分治思想實現時間效率的優化。

其實無論什麼演算法而言,都沒有更好最好之分,只有不適合與更適合之分,沒有最好的演算法,只有更適合的演算法,具體使用什麼演算法我們需要根據具體問題來判斷,使用最佳的演算法解決問題才是我們需要實現的!

(關於斐波那契數列第n項的運算,有興趣的可以了解了解利用矩陣的冪運算,然後再借助遞迴與分治實現,時間複雜度同樣可以降到o(logn),即矩陣快速冪)

第五講 經典演算法之排序演算法

3.最後說幾句 顧名思義,排序演算法就是將陣列中雜亂無章的數按照從小到大或者從大到小之類的順序進行排列的 程式。一般常見的排序演算法有氣泡排序 選擇排序 快速排序 歸併排序 堆排序 計數排序 桶排序 希爾排序等。例如 54 12 32 55 4 10 1 3 89 12 按從小到大 公升序 的順序進...

遞迴和分治演算法 經典題目

made by syx 2010年7月13日 21 05 27 迴圈賽日程表 快速排序 合併排序 棋盤覆蓋 有bug 求大數乘積 10進製,但有丟位 二分搜尋技術 整數劃分 階乘 迴圈賽日程表 include include using namespace std const int n 100 i...

經典演算法之遞迴演算法

前言何為遞迴?通俗理解就是在滿足某一條件的基礎上,重複執行某一 塊,直到不符合執行的條件為止。在開發過程中,很多場景會運用遞迴演算法來解決實際專案需求 但是遞迴有著最為致命的缺點,如果使用不慎,會使專案一直重複執行遞迴函式,直到系統丟擲stack over flow,所以在運用遞迴的時候,要慎之又慎...