myJavaEE

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

把递归算法转化为非递归算法, 有如下两种基本方法:
1)通过分析, 用迭代的方式自底向上. 有时需用栈保存参数
2)模拟函数调用过程, 用栈保存入参

 

尾递归:

一个函数只在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);    // 递归出口
    }

 

更通用点的伪代码:

    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。

posted on 2017-04-14 02:00  myJavaEE  阅读(3068)  评论(0编辑  收藏  举报