• 递归转换为迭代的一种通用方式


    把递归算法转化为非递归算法, 有如下两种基本方法:
    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。

  • 相关阅读:
    Kafka(3)--kafka消息的存储及Partition副本原理
    Kafka(2)--kafka基本原理之消息的分发与接收
    Kafka(1)--kafka基础知识
    ActiveMQ(4)---ActiveMQ原理分析之消息消费
    ActiveMQ(3)---ActiveMQ原理分析之消息持久化
    ActiveMQ(2)---ActiveMQ原理分析之消息发送
    Appium的常用定位方法
    appium报错信息:Could not extract PIDs from ps output. PIDS: [], Procs: ["bad pid 'uiautomator'"]”
    mysql服务启动不了解决方法
    Node.js安装及环境配置之Windows篇
  • 原文地址:https://www.cnblogs.com/myJavaEE/p/6706991.html
Copyright © 2020-2023  润新知