消递归(recursion)的一种方式

  author:tuiye@126.com

注:本文的例子开发的环境为WINXPVC 6.0

 

递归由于其函数栈嵌套的层数未定,在很多情况下,可能出现函数栈溢出,引起程序的崩溃。所以在某些情况下,认为的消除递归是非常有必要的。总的来说递归的消除的方式有2大类,一种为利用无限循环来消除,另一种是自己模拟栈(从heap中分配空间)来保存中间变量,来达到消递归的目的。在不同种类的消递归方式中,亦有自己不同的实现方式,本文利用模拟栈的方法来具体实现,兼以例子来说明。

 

我们现在以计算两个整数(intnm的最大公约数(dcg)为例来说明。

1)  如果利用递归方式,我们的程序可能如下(为了程序清晰):

/*dcg: recursion*/

int dcg_recursion(int n,int m)

{

    if ( n < m )

    {

        return dcg_recursion(m,n);

    }

    if ( 0 == m)

    {

        return n;

    }

    else

    {

        return dcg_recursion(m,n%m);

    }

}

此种方式中,递归的次数是未定(不可控),完全基于nm两个数;

 

2) 利用模拟栈的方式,我们程序如下:

//定义一个栈(或叫帧frame),用于保存临时数据

/*dcg: no recursion*/

typedef struct tagSt_DCG St_DCG;

struct tagSt_DCG

{

    St_DCG* pre;

    int n;

    int m;

       int l;

};

 

//no recursion入口

#define MC_DCG_NO_RECURSION(pstDcg,n,m,l) /

{/

     pstDcgTemp = (St_DCG*)malloc(sizeof(St_DCG));/

     memset(pstDcgTemp,0,sizeof(St_DCG));/

     pstDcgTemp->n = n;/

     pstDcgTemp->m = m;/

     if(pstDcg)/

     {/

              pstDcgTemp->pre = pstDcg;/

     }/

     pstDcg = pstDcgTemp;/

     pstDcgTemp = NULL;/

     goto NO_RECURSION_START;/

L_##l:/

     ;/

}

 

 

//no recursion出口

#define MC_RETURN(ra)/

{/

     pstDcgTemp = pstDcg;/

     if(!pstDcg){return ra;}/

     pstDcg = ((St_DCG*)pstDcg)->pre;/

     free(pstDcgTemp);/

     if(pstDcg)/

     {/

              goto NO_RECURSION_RETURN;/

     }/

     else/

     {/

              return ra;/

     }/

}

 

#define LBL(l) case l: goto L_##l;

 

int dcg_no_recursion(int n, int m)

{

    St_DCG* pstDcg = NULL;

     St_DCG* pstDcgTemp = NULL;

     int mid = 0;

   

NO_RECURSION_START:

    int ra = n;

     if(0 == m)

    {

        MC_RETURN(ra);

    }

    if (n < m)

    {

              mid=n;n=m;m=mid;

       MC_DCG_NO_RECURSION(pstDcg,n,m,1)

    }

 

    else

    {

              n = n%m;

        MC_DCG_NO_RECURSION(pstDcg,m,n,2)

    }

NO_RECURSION_RETURN:

    switch(pstDcg->l)

    {

       LBL(1)LBL(2)

    default:

        return ra;

    }

}

 

主要思想是,在本来递归调用自身函数的地方去保存一些数据(基本是为了回复现场用),然后不出自身函数,goto到函数的基本起始位置,这样就减少了调用函数时候的压栈与出栈的开销;在函数返回的地方调用模拟返回,判断是否已是模拟栈的最后一项,如是则出函数,返回最后结果,如否则利用goto到上一模拟栈终止的地方,继续执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值