遞歸轉換爲迭代的一種通用方式

把遞歸算法轉化爲非遞歸算法, 有以下兩種基本方法:
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

相關文章
相關標籤/搜索