數據結構第一節 遞歸
阿新 • • 發佈:2017-12-25
返回 分解 [] 非遞歸 最終 方法 高度 reverse 允許
分支轉向是算法的靈魂;函數和過程及其之間的相互調用,是在經過抽象和封裝之後,實現分支轉向的一種重要機制;而遞歸這是函數和過程調用的一種特殊形式,即允許函數進行自我調用。
遞歸的價值在於,許多應用問題都可簡潔而準確地描述為遞歸形式。
遞歸也是一種基本而典型的算法設計模式。這一模式可以對實際問題中反復出現的結構和形式做高度概括,並從本質層面加以描述與刻畫,進而導出高效的算法。從程序結構的角度,遞歸模式能夠統籌紛繁多變的具體情況,避免復雜的分支以及嵌套的循環,從而更為簡明的描述和實現算法,減少代碼量,提高算法的可讀性,保證算法的整體效率。
線性遞歸
int sum(int A[], intn) { //數組求和算法(線性遞歸版) if(n < 1) //平凡情況,遞歸基 return 0; //直接(非遞歸式)計算 else return sum(A, n -1) + A[n - 1];//遞歸:前n-1項和,再累積 第 n -1 項 }
減而治之
線性遞歸的模式,往往對應於所謂減而治之(decrease-and-conquer)的算法策略:遞歸沒深入一層,待求解問題的規模都縮減一個常數,直至最終蛻化為平凡的小(簡單)問題。
按照減而治之策略,此處隨著遞歸的深入,調用參數將單調地線性遞減。因此無論最初輸入的n有多大,遞歸的總次數都是有限的,故算法的執行遲早會終止,即滿足有窮性。當抵達遞歸基時,算法將執行非遞歸計算。
void reverse( int* A, int lo, int hi) { //數組倒置(多遞歸基遞歸版) if(lo < hi){ swap(A[lo], A[hi]); //交換A[lo]和A[hi] reverse(A, lo + 1, hi -1); //遞歸倒置A(lo, hi) }// else 隱含了兩種遞歸基 }
遞歸消除
void reverse( int* A, int lo, int hi){ //數組倒置,直接改造得到的非遞歸版 while( lo < hi){ swap(A[lo], A[hi]);//交換A[lo]和A[hi] lo ++; hi --;//收索待倒置區間 } }
二分遞歸
分而治之:將大的問題分解為若幹規模更小的問題,再通過遞歸機制分別求解。這種分解持續進行,直到子問題規模縮減至平凡情況。這也就是所謂的分而治之(divde-and-conquer)。
int sum( int A[], int lo, int hi){//數組求和方法(二分遞歸版) if(lo == li)//如遇到遞歸基(區間長度已將為1),則 return A[lo];//直接返回該元素 else{ int min = (lo + hi) >> 1; //以居中單元為界將原區間一分為2 return sum(A, lo, mi) + sum(A, mi + 1, hi); //遞歸對 各子數組求和,然後合計。 } }
數據結構第一節 遞歸