author:tuiye@126.com
注:本文的例子开发的环境为WINXP,VC 6.0
递归由于其函数栈嵌套的层数未定,在很多情况下,可能出现函数栈溢出,引起程序的崩溃。所以在某些情况下,认为的消除递归是非常有必要的。总的来说递归的消除的方式有2大类,一种为利用无限循环来消除,另一种是自己模拟栈(从heap中分配空间)来保存中间变量,来达到消递归的目的。在不同种类的消递归方式中,亦有自己不同的实现方式,本文利用模拟栈的方法来具体实现,兼以例子来说明。
我们现在以计算两个整数(int)n与m的最大公约数(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);
}
}
此种方式中,递归的次数是未定(不可控),完全基于n与m两个数;
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到上一模拟栈终止的地方,继续执行。