递归转非递归的编程思想

1.递归定义的函数在汇编层面很好理解,函数执行过程中对自身的调用实际上是指令的跳转,遇到调用自身的时候指令跳转到函数体的开始位置继续执行,这种跳转不可避免的打断当前函数的执行过程,当跳转部分的指令执行完毕,当前函数的执行过程又被恢复,这一恢复过程就用到了系统的栈,跳转发生之前,函数的相关参数已经保存在了栈中,跳转发生时又会把即将执行的下一条指令位置保存在栈中,也就是说当前函数的执行环境被很好的保存在了栈中。

2.递归转非递归就是用高级语言模拟这一汇编执行过程,因此这种转换一定是可行的,只是不同的递归模型其转换方式不一样。

3.拿到一个递归模型,可以看到问题的解答基本上可以分为两部分,一是根据当前执行环境问题不需要进一步分解了,通过若干步骤的运算即可得到结果;二是当前问题的解答有赖于子问题的解答,而且子问题的解出方式和当前问题相同,只是其执行环境会发生变化。我们的模拟也很简单,一个栈元素代表了一个问题的执行环境,每次我们取到栈顶元素进行执行,如果问题被解出那么代表该执行环境的栈顶元素会被弹出,同时根据当前问题的运算结果在其父问题中作用,设置其父问题的执行环境(父问题和其子问题的执行环境总是相邻);如果问题未被解出,那么子问题的执行环境会进栈(父问题被搁置),继续取栈顶元素,模拟问题的解答。需要注意的一点是随着递归的深入一定要有一个终极问题,终极问题的解出会导致父问题的解出(父问题的执行环境弹出),这种连锁反应最终以栈被清空作为结束,也就意味着始祖问题被解出了,模拟过程也就结束了。

汉诺塔问题为例:

//递归算法:
void hanoi(int n,char one,char two,char three)
 {
  void move(char x,char y);
  if(n==1)
     move(one,three);
  else
    {
     hanoi(n-1,one,three,two);
     move(one,three);
     hanoi(n-1,two,one,three);
    }
}
//非递归算法:
//栈的设计
struct stack{
int n;
char x,y,z;
int yn;//问题是否解出
int flag;//当前问题处于父问题的哪一个分支上,这个标志会影响当前执行过程对其父问题执行环境的修改
}st[1024];
int sttop=-1;
//非递归函数
void hanoi()
{
//循环体。每次循环取栈顶元素用以模拟一次执行过程。
while(sttop>-1)
{
//第一分支判断问题是否已解出
if(st[sttop].yn==1)
{
if(st[sttop].flag==1)
{
movd(st[sttop-2].x,st[sttop-2].z);
sttop--;
}
else if(st[sttop].flag==2)
{
st[sttop-1].yn=1;
sttop--;
}
if(st[sttop].flag==0)break;//此问题是始祖问题,计算结束
}
//第二分支判断当前问题是否是终极问题(意即此问题的解答变为非递归式解答)
else if(st[sttop].n==1)
{
move(st[sttop].x, st[sttop].z);
if(st[sttop].flag==1)
{
move(st[sttop-2].x, st[sttop-2].z);
sttop--;
}
else if(st[sttop].flag==2)
{
st[sttop-1].yn=1;
sttop--;
}
}
//第三分支当前问题没有解出,将子问题进栈
else
{
st[sttop+1].n=st[sttop].n-1;
st[sttop+1].x=st[sttop].y;
st[sttop+1].y=st[sttop].x;
st[sttop+1].z=st[sttop].z;
st[sttop+1].yn=0;
st[sttop+1].flag=2;

st[sttop+2].n=st[sttop].n-1;
st[sttop+2].x=st[sttop].x;
st[sttop+2].y=st[sttop].z;
st[sttop+2].z=st[sttop].y;
st[sttop+2].yn=0;
st[sttop+2].flag=1;
sttop+=2;
}
}
}
void main()
{
//始祖问题进栈
sttop++;
st[top].n=7;
st[top].x='A';
st[top].y='B';
st[top].z='C';
st[top].yn=0;
st[top].flag=0;
//开始计算
hanoi();
}

ackerman问题:

<script>
function stack(){}
stack.prototype.m=0;
stack.prototype.n=0;
stack.prototype.o=0;
stack.prototype.LMR=0;
stack.prototype.yn=0;
var sttop=-1
//初始化栈
var st=new Array(1024);
for(i=0;i<1024;i++)
{
st[i]=new stack();
}
//初始环境进栈
sttop++;
st[sttop].m=3;
st[sttop].n=2;
st[sttop].yn=0;
st[sttop].LMR=0;
st[sttop].o=0;
  
//非递归函数
function ackm()
{
while(sttop>-1){
if(st[sttop].LMR==0 && st[sttop].yn==1)return st[sttop].o;
if(st[sttop].yn==1)
{
if(st[sttop].LMR==1)
{
st[sttop-1].o=st[sttop].o;
st[sttop-1].yn=1;
sttop--;
}
else if(st[sttop].LMR==2)
{
st[sttop-1].n=st[sttop].o;
sttop--;
}
else if(st[sttop].LMR==3)
{
st[sttop-1].o=st[sttop].o;
st[sttop-1].yn=1;
sttop--;
}
}
else{
if(st[sttop].m==0)
{
st[sttop].o=st[sttop].n+1;
if(st[sttop].LMR==1)
{
st[sttop-1].o=st[sttop].o;
st[sttop-1].yn=1;
sttop--;
}
else if(st[sttop].LMR==2)
{
st[sttop-1].n=st[sttop].o;
sttop--;
}
else if(st[sttop].LMR==3)
{
st[sttop-1].o=st[sttop].o;
st[sttop-1].yn=1;
sttop--;
}
  
}
else if(st[sttop].n==0)
{
st[sttop+1].m=st[sttop].m-1;
st[sttop+1].n=1;
st[sttop+1].LMR=1;
st[sttop+1].yn=0;
sttop++;
}
else
{
st[sttop+1].m=st[sttop].m-1;
st[sttop+1].LMR=3;
st[sttop+1].yn=0;
  
st[sttop+2].m=st[sttop].m;
st[sttop+2].n=st[sttop].n-1;
st[sttop+2].LMR=2;
st[sttop+2].yn=0;
  
sttop+=2;
}
}
}//循环结束
}//函数结束
alert(ackm());
</script>

 

posted @ 2013-08-08 19:43  SKY_VIEW  阅读(519)  评论(0编辑  收藏  举报