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

本文介绍了阿克曼函数的递归与非递归实现,重点解析了非递归算法的思路和关键步骤。通过建立栈来模拟递归过程,详细阐述了如何存储和处理m、n的值,以及如何解决双递归问题。作者以(2,1)为例展示了栈的变化,帮助读者更好地理解非递归实现的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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)为例,栈的变化图解

第一次发博客,有错误的地方希望大家多多指教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值