递归转非递归(13条消除规则)

直接递归的消去规则:
 基本思路:将递归调用的地方用等价的非递归代码来代替,并对return语句做适当处理。
13条规则:处理直接递归调用和return语句,将之转换成等价的迭代代码。

初始化  
   ⑴ 在过程的开始部分,插入说明为栈的代码并将其初始化为空:  StackType Stack[1..SIZE]
      Top ← 0
    在一般情况下,这个栈用来存放参数、局部变量和函数的值、每次递归调用的返回地址。
   ⑵ 将标号L1附于第一条可执行语句。
      ...  
   L1:第一条可执行语句
      ...
 然后对于每一处递归调用都用一组执行下列规则的指令来代替。
 处理递归调用语句
  ⑶ 将所有参数和局部变量的值存入栈。
     Top ← Top +1
     Stack[Top] ← …
     栈顶指针可作为一个全程变量来看待。
  ⑷ 建立第i个新标号Li,并将标号的下标i存入栈。这个标号的i值将用来计算返回地址。
     Top ← Top +1
     Stack[Top] ← i
     此标号放在规则⑺所描述的程序段中。
  ⑸ 计算这次调用的各实在参数(可能是表达式)的值,并把这些值赋给相应的形式参数。

⑹ 插入一条无条件转向语句转向过程的开始部分:
      goto L1

  (以上完成一次递归调用)
对退出点的处理
  ⑺ 如果这过程是函数,则对递归过程中含有此次函数调用的那条语句做如下处理:将该语句的此次函数调用部分用从栈顶
取回该函数值的代码来代替,其余部分的代码按原描述方式照抄,并将⑷中建立的标号附于这条语句上。

如果此过程不是函数,则将⑷中建立的标号附于⑹所产生的转移语句后面的那条语句。

以上步骤消去过程中的递归调用。

下面对过程中出现return语句进行处理。
  注:纯过程结束处的end可看成是一条没有值与之联系的return语句
对每个有return语句的地方,执行下述规则:
 
  ⑻ 如果栈为空,则执行正常返回。
     if top = 0 then return(…)
 
  ⑼ 否则,将所有输出参数(带有返回值的出口参数,out/ inout型)的当前值赋给栈顶上的那些对应的变量。
     
     Stack[n] ← …
  ⑽ 如果栈中有返回地址标号的下标,就插入一条此下标从栈中退出的代码,并把这个下标赋给一个未使用的变量。
     addr ← Stack[Top]
     Top ← Top -1
  ⑾ 从栈中退出所有局部变量和参数的值并把它们赋给对应的变量。

⑿ 如果这个过程是函数,则插入以下指令,这些指令用来计算紧接在return后面的表达式并将结果值存入栈顶。
     Top ← Top +1
     Stack[Top] ←表达式的值

⒀ 用返回地址标号的下标实现对该标号的转向。
     if addr = i then goto Li

递归转非递归(13条消除规则)

时间: 2024-10-28 22:08:02

递归转非递归(13条消除规则)的相关文章

递归转非递归(实例)

递归调用示例算法1.10  求取数组元素的最大值(递归算法)    procedure MAX1(i)    // 查找数组A中最大值元素,并返回该元素的最大下标.//        global integer n,A(1:n),j,k        integer i        if i<n then j←MAX1(i+1)  //递归调用//               if A(i) > A(j) then k←i                   else k←j       

简单迷宫算法(递归与非递归C++实现)

假定迷宫如下:1代表墙,0代表道路,起点在(1,1),终点(11,9)(PS:下标从0开始计算). 现在寻求一条路径能从起点到达终点(非最短). 有两种解法:递归与非递归. 递归算法思路: 要用递归,就要寻找一个子问题,该子问题是递归的.很明显,这道题的子问题就是从8个方向(上下左右还有四个斜角)中寻找一个可行方向并向前走一步,该子问题(seekPath函数)的实现代码如下: 1 struct offset{ 2 int x; 3 int y; 4 }; 5 offset move[8]={{-

二叉树遍历递归与非递归实现

说明:本文仅供学习交流,转载请标明出处,欢迎转载! 二叉树遍历是二叉树中非常基础的部分,也是学习二叉树必须熟练掌握的部分,下面我们先给出二叉树三种遍历方式的定义,并通过举例来说明二叉树遍历的过程. 二叉树的遍历分为:前序遍历(也叫先序遍历).中序遍历.后序遍历.所谓前.中.后都是根据当前子树根结点相对左右孩子的位置而言,也就是说: 前序遍历:根结点在前,即:根 ----->左------->右: 中序遍历:根结点在中间,即:左------>根------>右: 后序遍历:根结点在最

树的递归与非递归遍历总结

树的递归遍历遍历很简单,非递归遍历要复杂一些,非递归先序.中序.后序遍历需要用一个辅助栈,而层次遍历则需要一个辅助队列. 树的结构: 1 public class Tree<T> { 2 private T data; 3 private Tree<T> left; 4 private Tree<T> right; 5 ... 6 } 用策略模式定义一个访问工具: 1 public interface Visitor<T> { 2 void process(

二叉树三种遍历(递归以及非递归实现)

package com.shiyeqiang.tree; import java.util.Stack; public class BiTree { public static void main(String[] args) { // 首先构造叶子节点 BiTree leafA1 = new BiTree(4); BiTree leafA2 = new BiTree(5); BiTree leafB1 = new BiTree(6); BiTree leafB2 = new BiTree(7)

二叉树遍历算法总结(递归与非递归)

一:前言 二叉树的遍历方法分四种:前序,中序,后序以及层次遍历. 其中,前中后遍历方法的实现分递归和非递归,非递归遍历的实现需要借助于栈. 实际上,递归的调用就是一种栈的实现,所以,非递归遍历就需要人工借助栈结构来实现. 而层次遍历需要借助队列. 二:前中后序遍历 递归遍历: 递归遍历的思想和方法很简单,通过调整输出语句来实现前,中,后三种遍历. 代码如下: 1 void show(BiTree T) 2 { 3 if(T) 4 { 5 printf("%c ",T->data)

二叉树递归与非递归遍历,最近公共父节点算法

#include <iostream> #include <stack> using namespace std; #define MAX 100 //字符串最大长度 typedef struct Node //二叉树结点 { char data; Node *lchild,*rchild; } *Btree; void createBT(Btree &t); //先序构造二叉树 void preorder(Btree &t); //二叉树递归先序遍历 void i

递归与非递归及其相互转换

一.什么是递归 递归是指某个函数直接或间接的调用自身.问题的求解过程就是划分成许多相同性质的子问题的求解,而小问题的求解过程可以很容易的求出,这些子问题的解就构成里原问题的解了. 二.递归的几个特点 1.递归式,就是如何将原问题划分成子问题. 2.递归出口,递归终止的条件,即最小子问题的求解,可以允许多个出口. 3.界函数,问题规模变化的函数,它保证递归的规模向出口条件靠拢 三.递归的运做机制 很明显,很多问题本身固有的性质就决定此类问题是递归定义,所以递归程序很直接算法程序结构清晰.思路明了.

二叉树之AVL树的平衡实现(递归与非递归)

这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现. 下面这张图绘制了需要旋转操作的8种情况.(我要给做这张图的兄弟一个赞)后面会给出这八种情况对应平衡实现. [1] 情况1-2: 这种需要旋转的结构一般称之为LL型,需要右旋 (顺时针旋转). 我用一个图来抽象一下这两个情况,画的不好,我尽量表达吧. 此时需要对A进行平衡操作,方法为: 将A的左子树换为B的右子树. B的右子树换为A. 非递归实现的代码为: 1 void rotate