C语言,关于阿克曼函数非递归实现的一点拙见

第一次写博客,初学数据结构,以下是我对阿克曼函数非递归实现的一点拙见,有错误的地方,欢迎大家批评指教。

1.初识阿克曼函数
我们先来看看阿克曼函数的形式
已知Ackerman函数的定义如下:
n+1 m=0
akm(m, n) = akm(m-1, 1) m≠0,n=0
akm(m-1, akm(m, n-1) m≠0,n≠0
阿克曼函数是以递归的形式给出的,采用递归算法解决这个问题是很直接的
//Ackerman 递归实现算法
ElemTypy Ackerman(ElemType m,ElemType n)
{//输入m,n的值,返回函数结果值
if(m == 0) result = n+1;
else if(m != 0 && n == 0) result = Ackerman(m-1,1);
else result = Ackerman((m-1,Ackerman(m,n-1)));
return result;
}//Ackerman

2.阿克曼函数的非递归实现
我认为,要想完成阿克曼函数的非递归实现,有三点十分重要。
①.要清楚阿克曼函数的递归算法,本质上是是如何实现的,了解之后我们发现,递归的本质,是用系统的栈存储了递归过程产生的地址和变量。
②.了解到递归的本质之后,我们就可以设想,自己建立一个栈,手动(用自定义函数) 来实现入栈和出栈操作。
③.当我们想到用自己建立的栈去实现非递归时,紧接着的问题就是,用这个栈去存储什么内容? 要想解决这个问题,我们需要仔细研究阿克曼函数本身,研究之后,我们发现,函数的出口,在“m = 0”时,输出的是值“n+1”,我觉得看到这一点对于理解下面的非递归实现代码非常重要。
我们还可以发现,输入一个m,n,要求得函数值,不过是m,n不停地变化,不停地带入,一层一层求解,最终再返回到我们要求的问题的过程,于是建立两个存储m,n的值的栈的思想就萌生了。

我们来重点理解一下非递归实现的算法:
int Ackerman(int m,int n) /函数的返回值是整型,也就是 我们前面提到的出口“n+1”的值/
{
STACK S,T; //建立两个栈S,T,分别用来存储m,n的值
S = InitStack();
T = InitStack();
Push(&S,m);
Push(&T,n); /将输入的m,n值压入栈,怎么更好的理解把这两个数压入栈到底是什么意思呢? 我的理解是,把这两个数压入栈就像是向输入计算机输入你要求的问题,计算机把这两个数存起来,然后按照程序执行,如果可以得到结果(比如m=0的情形),那就回答你的问题,并且清除你输入的参数,如果不能直接解决,那就先保留这两个数,然后走到下一步程序,看能不能解决,如果能解决,那就返回结果给上一层,如果不能保留,就继续往下走,问题走到尽头的时候,一定会得到解决,再一层一层得返回结果,最终求得问题的答案/
while(StackEmpty(&S)) /当栈不为空时,进行循环/
{
while(m != 0)
{
if(n == 0)
{ //m!=0 && n == 0 的情况
m = m-1;
n = 1;
Push(&S,m);
Push(&T,n); /将改变后的m,n值压入栈/
}
else
{
n = n-1;
Push(&S,m-1);
Push(&T,-1); /这一步是m,n都不为0的情况,非常特殊,因为这一步是一个双递归的过程,我们要向走通这一步,就要先解决最内层的递归,然后再解决外层递归,为此,我们将m-1压入S栈,-1压入T栈,-1是一个标志,用来标识这种特殊情况。 我们还发现,这一步我们把n复制为n-1,但是没有对m重新赋值,这也是为了要求先求出内层递归的值akm(m, n-1),当求出这个值之后,我们用求得的值赋把T栈中该位置的-1替换掉,就成功走通这一步啦!/
}
}
n = n+1; /当m等于0时,按照函数法则执行,给n赋值n+1/
while(StackEmpty(&S) && *(T.top-1) != -1)
{
Pop(&S);
Pop(&T);
}/这一步可以和我上面提到的情况特殊那一步联系起来,当你最终求得akm(m, n-1)时(其实也就是求得的T栈中-1位置本应该压入的n的值),我们的目的达到了,就可以把S,T栈中没用的信息全都弹出,回到我们要解决的问题的位置/
if(StackEmpty(&S))
{
m = *(S.top-1);
Pop(&T);
Push(&T,n);
}/但我们回到了我们要解决的问题的位置(把-1压入栈的位置),由于我们再计算内层递归的时候,改变了m的值,这里我们把m赋值为我们之前把-1压入T栈的同时,压入S栈的“m-1”,也就是此时S栈的栈顶元素/
}

return n;    /*当整个循环完成时,返回n的值,就是我们想要的最终答案*/

}

3.以(2,1)为例,栈的变化图解以(2,1)为例的栈的变化图解
第一次发博客,有错误的地方希望大家多多指教

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值