将递归函数转化为非递归再讨论

将递归函数转化为非递归再讨论


  突然发现很早以前就写过关于递归转化为非递归函数的两篇博文,当时都是自以为懂,认为我会转化,不就是一个栈吗,大致原理我都知道,只不过具体算法写起来耗费一点时间而已。是的。这样说没什么问题。
 
  但是我很喜欢cs:app(ics)即深入理解计算机系统课本上一句话,不要欺骗自己说我大致懂原理,不必纠结于具体细节不必过多练习了。比如这个问题,以前自以为自己懂,但是写得不熟练,其实是理解不够深刻。学了半学期ics,写了看了很多汇编代码调用递归函数以后,我对递归转化为非递归理解地更深刻了。甚至理论上可以写出汇编风格的C语言代码,转化递归非递归自然可以了。下面我们结合汇编实现方法,基于练习了大量汇编代码的基础上,再来看看这个细节并不简单的问题。

下面来看看数算课本里对机械做法的介绍
 1. 设置一工作栈保存当前工作记录
 2. 设置 t+2个语句标号
 3. 增加非递归入口
 4. 替换第 i (i = 1, …, t)个递归规则
 5. 所有递归出口处增加语句:goto label t+1;
 6. 标号为t+1的语句的格式
 7. 改写循环和嵌套中的递归
 8. 优化处理

只完成机械转化,不考虑7.8.,下面我们讨论两个问题:
1.需要在工作状态里保存些什么?
  类比汇编代码写法我们知道,要保存自变量,返回地址,不需要保存结果,只需要一个全局变量保存结果即可。
2.t到底是什么?
  课本里面说t是递归规则数目,个人觉得不是很清楚(自己搞懂以后才明白课本在说什么),不如说是递归内部return address种类更好一点,也就是说t就是递归调用自身方式数目。

讨论清楚这些问题,可以看看有些汇编风格的非递归代码。
  


#include<stdio.h>

struct info_type
{
    int m,n;
    int ra;//return address;
    info_type(){};
    info_type(int _m,int _n,int _ra):m(_m),n(_n),ra(_ra){};
};

const int SIZE=10000;
info_type stack[SIZE];
int sp=-1;//stack_pointer


void push(info_type val)
{
    stack[++sp]=val;
    return;
}

info_type top()
{
    return stack[sp];
}

void pop()
{
    --sp;
}

int ack(int m,int n)
{
    info_type info;
    int ans;
    push(info_type(m,n,0));
    goto Lcall;

Lcall:
    info=top();
    if (info.m==0)
    {
        ans=info.n+1; 
        goto Lret;
    }
    if (info.n==0)
    {
        push(info_type(info.m-1,1,1));
        goto Lcall;
    }
    push(info_type(info.m,info.n-1,2));
    goto Lcall;

L1:
    goto Lret; 

L2:
    info=top();
    push(info_type(info.m-1,ans,3));
    goto Lcall;

L3:
    goto Lret;

Lret:
    info=top();
    pop();
    if (info.ra==0)
        return ans;
    if (info.ra==1)
        goto L1;
    if (info.ra==2)
        goto L2;
    if (info.ra==3)
        goto L3;
}

int ack_test(int m,int n)
{
    if (m==0)
        return n+1;
    else if (n==0)
        return ack_test(m-1,1);
    else
        return ack_test(m-1,ack_test(m,n-1));
}

int main()
{
    bool test=true;
    for (int i=0;i<4;i++)
        for (int j=0;j<4;j++)
            if (ack(i,j)!=ack_test(i,j))
            {
                printf("Wrong Answer! ack(%d,%d)=%4d , instead of %4d\n",
                    i,j,ack_test(i,j),ack(i,j));
                test=false;
            }
    if (test)
        printf("Accepted!\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值