計算機演算法設計與分析——遞迴與分治策略(一)
遞迴:
直接或者間接地呼叫自身的演算法稱為遞迴。用函式自身給出定義的函式成為遞迴函式。
使用遞迴技術往往使函式的定義和演算法的描述簡潔且易於理解。有些資料結構,如二叉樹等,由於其本身固有的遞迴特性,特別適合用遞迴的形式來描述。另外,還有一些問題,雖然其本身沒有明顯的遞迴結構,但用遞迴技術來求解,可以使得設計出的演算法簡捷易懂且易於分析。
每個遞迴函式都必須有非遞迴定義的初始值,否則,遞迴函式就無法計算。
遞迴演算法的例項:
階乘函式:
n!=1 (n=0)
n!=n(n-1)! (n>0)
遞迴程式碼:
int faction(int n)
{
if(n==0)
return 1;
else
return n*faction(n-1);
}
Fibonacci數列:
無窮數列1,1,2,3,5,8,13,21,34……,稱為Fibonacci數列。
遞迴程式碼:
int fibonacci(int n)
{
if(n<=1)
return 1;
else
return fibonacci(n-1)+fibonacci(n-2);
}
Hanoi塔問題
設a,b,c是三個塔座,在塔座a上有一疊共n個圓盤,這些圓盤自下而上,由大到小的疊放在一起,各圓盤從小到大的編號為1,2,……,n。現要求將塔座a上的這一疊圓盤移動到塔座b上,並仍按照同樣的順序疊放,在移動圓盤時應遵守以下的移動規則:
規則(1) 每次只能移動一個圓盤
規則(2) 任何時刻都不允許將較大的圓盤壓在較小的圓盤之上
規則(3) 在滿足移動規則(1)和(2)的前提下,可將圓盤移動至a,b,c中任何一個塔座上
這個問題有一個簡單的解法,假設塔座a,b,c排成一個三角形,構成一個順時針的迴圈。在移動圓盤的過程中,若是奇數次移動,則將最小的圓盤移動到順時針方向的下一個塔座上,若是偶數次移動,則保持最小的圓盤不動,而在其他兩個塔座之間,將較小的圓盤移動到另一座塔座上。
運用遞迴技術解決這個問題,當n=1時,只要將編號為1的圓盤從塔座a直接移動到b就可以了。當n>1時,需要利用塔座c作為輔助塔座,此時要設法將n-1個較小的圓盤依照移動規則從塔座a移動到c,然後將剩下的最大的圓盤從a移動到b,最後再設法將n-1個較小的圓盤依照移動規則從c移動到b。
由此可見,n個圓盤的移動問題可以分解為兩次n-1個圓盤的移動問題。這又可以遞迴的用上述方法來做,所以Hanoi塔的遞迴演算法如下:
void hanoi(int n,int a,int b,int c)
{
if(n>0)
{
hanoi(n-1,a,c,b);
move(a,b);
hanoi(n-1,c,b,a);
}
}
其中,hanoi(n,a,b,c)表示將a上自下而上,由大到小疊放在一起的n個圓盤依照移動規則移動到b上,並且仍然按照同樣的順序疊放。在移動的過程中,以塔座c作為輔助塔座,move(a,b)表示將a上編號為n的圓盤移動到b上。
遞迴演算法總結:
像hanoi這樣的遞迴演算法,在執行時需要多次呼叫自身,實現這種遞迴呼叫的關鍵是為演算法建立遞迴呼叫的工作棧。通常,在一個演算法中呼叫另一個演算法,系統需要在執行被呼叫演算法之前先完成三件事:
(1)將所有實參指標、返回地址等資訊傳遞給被呼叫演算法。
(2)為被呼叫演算法的區域性變數分配儲存區。
(3)將控制轉移到被呼叫演算法的入口。
從被呼叫演算法返回撥用演算法時,系統也要相應的完成三件事情:
(1)儲存被呼叫演算法的計算結果。
(2)釋放分配給被呼叫演算法的資料區。
(3)依照被呼叫演算法儲存的返回地址將控制轉移到呼叫演算法。
遞迴演算法中,當有多個演算法被呼叫時,按照後呼叫先返回的原則進行。演算法之間的資訊傳遞和控制轉移必須通過棧來實現,即系統將整個程式執行時所需要的資料空間安排在一個棧區中,每呼叫一個演算法,就為這個演算法在棧頂分配一個儲存區,每退出一個演算法,就釋放它在棧頂的儲存區。當前正在執行的演算法的資料一定在棧頂。遞迴演算法的實現類似於多個演算法的巢狀呼叫,只不過呼叫演算法和被呼叫演算法是同一個演算法。
由於遞迴演算法結構清晰,可讀性強,且容易被數學歸納法證明演算法的正確性,因此它為設計演算法、除錯程式帶來了很大的方便,然而,遞迴演算法的執行效率很低,無論是耗費的計算時間還是佔用的儲存空間都比非遞迴演算法要多。若在程式中取消遞迴演算法的呼叫,則其執行時間可以大大的減少。因此,有時希望在遞迴演算法中消除遞迴呼叫,使其變成一個非遞迴演算法,例如,採用一個使用者定義的棧來模擬系統的遞迴呼叫工作棧,從而到達將遞迴演算法改為非遞迴演算法的目的。當然僅僅是機械的模擬還不能達到減少計算時間和減少儲存空間的目的,還要根據具體程式的特點對遞迴呼叫的工作棧進行簡化,儘量的減少工作棧的操作,壓縮棧儲存空間以達到節省計算時間和儲存空間的目的。
相關文章
- 計算機演算法設計與分析筆記(二)——遞迴與分治計算機演算法筆記遞迴
- 遞迴與分治演算法練習遞迴演算法
- 遞迴 & 分治演算法深度理解遞迴演算法
- 快取遞迴計算快取遞迴
- 演算法設計與分析(fd)演算法
- 演算法小專欄:遞迴與尾遞迴演算法遞迴
- 計算機網路之策略路由與雙機熱備計算機網路路由
- 演算法設計與分析中的幾個核心演算法策略:動態規劃、貪心演算法、回溯演算法和分治演算法演算法動態規劃
- 演算法設計與分析---論序演算法
- 演算法設計與分析-01歐幾里得演算法
- C++ 遞迴與物件導向程式設計基礎C++遞迴物件程式設計
- 我與計算機計算機
- 遞迴演算法程式設計整數因子分解問題的遞迴演算法遞迴演算法程式設計
- 揹包問題的遞迴與非遞迴演算法遞迴演算法
- 遞迴程式的漸近分析(以分治為例)遞迴
- 演算法分析與設計 - 作業1演算法
- 演算法分析與設計 - 作業2演算法
- 演算法分析與設計 - 作業3演算法
- 演算法分析與設計 - 作業5演算法
- 演算法分析與設計 - 作業6演算法
- 計算機組成與設計(4)-----處理器計算機
- 計算機叢集與網格計算計算機
- 人腦與計算機計算機
- 計算機器與智慧計算機
- 【演算法分析與設計】輾轉相除法演算法
- 計算機組成與系統結構 cache 原理與計算計算機
- 遞迴物件的設計模式遞迴物件設計模式
- 資料結構與演算法:遞迴資料結構演算法遞迴
- 歸併排序(C++_分治遞迴)排序C++遞迴
- 第三章——演算法設計與分析演算法
- 視差和深度分析與計算
- 1223 遞迴下降語法分析程式設計遞迴語法分析程式設計
- 遞迴與goto (轉)遞迴Go
- 端遊HUD設計實踐與策略
- 12、Python與設計模式–策略模式Python設計模式
- 如何區分計算機策略計算機
- 系統架構設計筆記(87)—— 計算機病毒與防治架構筆記計算機
- 二十一、氣泡排序演算法——JAVA實現(遞迴與非遞迴)排序演算法Java遞迴