把遞歸算法轉化爲非遞歸算法, 有以下兩種基本方法:
1)經過分析, 用迭代的方式自底向上. 有時需用棧保存參數
2)模擬函數調用過程, 用棧保存入參java
尾遞歸:算法
一個函數只在return處調用自身。不少編譯器就能將其轉換爲迭代函數
T tailRecursive(U x, V y) { if (bar(x, y)) { return exit(x,y); } else { ... // block 1 return tailRecursiveFoo(w, z); } } To: T Iterative(U x, V y) { while (!bar(x, y)) { // 調用遞歸子函數的條件if -> while ... // block 1 x = w; // 傳入遞歸子函數的參數 y = z; } return exit(x,y); // 遞歸出口 }
更通用點的僞代碼:spa
T recursiveFoo(U param1, V param2){ U local1; V local2; ... // code block 1 recursiveFoo (local1, local2); ... // code block 2 recursiveFoo (param1, local2); ... // code block 3 recursiveFoo (local1, param2); ... // code block 4 } To: T iterativeFoo (U param1, V param2) { U local1; V local2; Stack stk; stk.push(javaBean:{param1, param2, local1, local2, 1}); // 進入函數, 第一次調用: 建立棧並將局部變量壓棧 while (!stk.empty()) { // 循環直至棧空 + 彈棧 FooStackInfo stkTop = stk.pop(); param1 = stkTop.param1; param2 = stkTop.param2; local1 = stkTop.local1; local2 = stkTop.local2; switch (stkTop.location) { // 遞歸塊->switch-case包裹 case 1: ... // code block 1 //向前匹配塊 stk.push(javaBean:{param1, param2, local1, local2, 2}); //第二次調用 stk.push(javaBean:{local1, local2, local1, local2, 1}); //傳參 break; case 2: ... // code block 2 //向前匹配塊 stk.push(javaBean:{param1, param2, local1, local2, 3}); //第三次調用 stk.push(javaBean:{param1, local2, local1, local2, 1}); //傳參 break; case 3: ... // code block 3 //向前匹配塊 stk.push(javaBean:{param1, param2, local1, local2, 4}); //第四次調用 stk.push(javaBean:{local1, param2, local1, local2, 1}); //傳參 break; case 4: ... // code block 4 //程序末尾(無匹配) break; } } }
注: 若是遞歸子函數都在一塊兒且在遞歸母函數程序的末尾,則無需記錄調用位置且無需使用switch case,只須要push。code