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

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

时间: 2024-10-10 23:31:51

递归转换为迭代的一种通用方式的相关文章

[转]在计算机程序中,完成重复的任务有两种方式:递归和迭代(循环)。

在计算机程序中,完成重复的任务有两种方式:递归和迭代(循环) 递归的一个例子:从前有座山,山里有座庙,庙里一个老和尚在给小和尚讲故事,内容是“从前有座山,山里有座庙,庙里一个老和尚在给小和尚讲故事,内容是“从前有座山,山里有座庙,庙里一个老和尚在给小和尚讲故事,内容是“...... 循环的一个例子:炉子上有99锅汤,让我不小心喝了一锅,炉子上还有98锅汤;炉子上有98锅汤,让我不小心喝了一锅,炉子上还有97锅汤;炉子上有97锅汤,让我不小心喝了一锅,炉子上还有96锅汤; ...... http:

递归和迭代两种方式实现归并排序(Java版)

递归版 package MergeSort; import Utils.SortUtils; /** * 归并排序递归版 * @author liguodong */ public class Demo02 { public static void mergeSort(int[] a){ mSort(a, a, 0, a.length-1); } /** * * @param SR为待排序的数据 * @param TR1为排序之后的数据 * @param s * @param t */ publ

[LeetCode系列]爬梯问题的递归解法转换为迭代解法

有一个n阶的梯子, 你每次只能爬1阶或2阶, 请问共有多少种登顶的爬法?(正好爬完n阶, 不能多也不能少) 本题最优解是直接套用菲波那切数列即可(因为菲波那切数列的第n个元素正好等于第n-1个元素和第n-2个元素的和, 与本题的要求完全相同). 递归解法: 1 int climbStairs(int n) { 2 if (n < 3) return n; 3 return climbStairs(n-1) + climbStairs(n-2); 4 } 思路很清晰, 递归到当前阶数小于3阶时返回

链表翻转的图文讲解(递归与迭代两种实现)

链表的翻转是程序员面试中出现频度最高的问题之一,常见的解决方法分为递归和迭代两种.最近在复习的时候,发现网上的资料都只告诉了怎么做,但是根本没有好好介绍两种方法的实现过程与原理.所以我觉得有必要好好的整理一篇博文,来帮忙大家一步步理解其中的实现细节.  我们知道迭代是从前往后依次处理,直到循环到链尾:而递归恰恰相反,首先一直迭代到链尾也就是递归基判断的准则,然后再逐层返回处理到开头.总结来说,链表翻转操作的顺序对于迭代来说是从链头往链尾,而对于递归是从链尾往链头.下面我会用详细的图文来剖析其中实

二叉树总结—建树和4种遍历方式(递归&amp;&amp;非递归)

今天总结一下二叉树,要考离散了,求不挂!二叉树最重要的就是 建立.4种遍历方式,简单应用,如何判断两颗二叉树是否相似 二叉树分为 :1.完全二叉树  2.满二叉树 结构性质: 1).满二叉树 高度为h ,节点数则为 2^h - 1,且叶子节点全在最下层,且叶子节点数为2^(n-1)个{n代表二叉树层数,也叫深度} 2).n个节点的 完全二叉树 深度为 int(log2n)(以2为底n的对数)+ 1: 3).非空二叉树 叶子节点个数==双分支节点数+1 4).非空二叉树 某节点编号 n  若有左孩

JAVA中断迭代的几种方式

JAVA中断迭代的几种方式 本文总结一下JAVA中中断迭代的几个关键字的用法,return就不说了,重点说一下break和continue以及JAVA中怎样实现其他语言中的goto关键字的用法. break和continue的区别 两者都有跳出循环的作用,不同的是break跳出循环后,直接终止了for或者while循环,不会执行后面的迭代,而continue跳出循环指的是跳出本次迭代,接着执行下一次迭代. goto介绍 goto起源于汇编语言的程序控制,若A成立,则跳到这里,否则跳到那里. 尽管

二叉树的三种遍历方式的循环和递归的实现方式

///////////////////头文件:BST.h//////////////////////// #ifndef BST_H #define BST_H #include "StdAfx.h" #include<iostream> #include<stack> template<typename DataType> class BST { public: class Node { public: Node(int data=0):m_dat

STM32 通用定时器的几种配置方式

STM32 通用定时器的几种配置方式 //------------------------------------------------------------------------------ // 1.普通定时使用 #include"stm32f10x.h" #include"time.h" static Time_NVIC_Config( void ) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_SetVecto

递归与迭代【转】

1 递归的基本概念:程序调用自身的编程技巧称为递归,是函数自己调用自己. 一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合. 1.1 使用递归要注意的有两点: 1)递归就是在过程或函数里面调用自身: 2)在使用递归时,必须有一个明确的递归结束条件,称为递归出口. 1.2 递归分为两个阶段: 1)递推:把复杂的问题的求解推到比原问题简单一些的问题的求解: 2