关于阿克曼函数(akermann)非递归算法的一点见解 c++

关于阿克曼函数(akermann)非递归算法的一点见解

0

这个星期,数据结构与算法的陈老师布置了一道题目,要求用非递归的算法计算阿克曼函数。在百度上找了很多个网址,都没有找到我想要的答案。于是,在我做出来之后,打算与大家分享一下我自己的想法。不足之处,请多多指教!

阿克曼函数的形式

如下图是我从《数据结构与程序设计》翻译版描述的阿克曼函数。Alt
看到阿克曼函数的这个形式,毫无疑问第一个想到的肯定是用递归的算法。但是如果不用递归的算法,事情就变得麻烦起来了。

分析

说到用其它的算法代替递归算法,大部分第一个想到的肯定是使用循环,我第一个想到的也是循环,这是正确的。但是这个问题比较特殊,特殊之处就在于它的问题的出现是线性的。也就是说,你想要解决上一个问题,你只需要解决这一个问题;你想要解决这一个问题,你只需要解决下一个问题。注意我这里的用词:只需要!!!递归的实现其实就是一个堆栈出栈的过程。
Alt
下面就以计算A(2,1)的例子分析。如下图。
Alt
(注:这个图上的元素应该从下往上看,像堆栈一样)
如图,我们要解决A(2,1),就得解决A(1,A(2,0));要解决A(1,A(2,0)),就得解决A(2,0)… 以此类推,直到我们得到一个m=0的元素A(0,1),A(0,1)解决了之后,它的结果可以一直回到原来要解决的问题A(1,A(2,0)),也即是A(1,3)。往后同样分析,要解决A(1,3),就得先解决A(0,A(1,2));要解决A(0,A(1,2)),就得先解决A(1,2)…直到我们最终推出A(2,1)的结果为止,最终的结果是5。

如何写代码

从上面的分析,我们可以发现:
(1)每一个需要计算的元素是一个个向上地堆栈,直到遇到m=0的情况,此时A(0,n)可以计算出一个整数,之后就是出栈的操作。
(2)A(m,A(m1,m2)),这种情况在栈中是比较特殊的情况,当这里的m=0时,栈就能继续出栈了;但是m≠0的时候,我们还得继续向上堆栈。

解决办法

(1)声明两个栈s1、s2。
   s1存储m
   s2存储n
(2)遇到A(m,A(m1,m2))这种情况的时候,将n存储为-1,这是为了后面出栈的算法能够识别特殊情况,并且做出相应的处理。
(3)声明m和n,用于动态存储并操作m值和n值,这是因为在(2)的要求下,n可能在栈s2中存为-1,此时存储的值是一个待定值。

代码

#include<iostream>
#include<stack>
using namespace std;
int asker(int m, int n)
{
	stack<int> s1;
	stack<int> s2;
	s1.push(m);
	s2.push(n);
	while (!s1.empty())
	{
		while (m != 0)
		{
			if (n == 0)
			{
				m = m - 1;
				n = 1;
				s1.push(m);
				s2.push(n);
			}
			else
			{
				n = n - 1;
				s1.push(m - 1);
				s2.push(-1);
			}
		}
		n = n + 1;
		while ((!s1.empty())&& (s2.top() != -1))
		{
			s1.pop();
			s2.pop();
		}
		if(!s1.empty())
		{
			m = s1.top();
			s2.pop();
			s2.push(n);
		}
	}
	return n;
}
void main()
{
	cout << asker(2, 1);
}

1

这是我第一次写博客,有很多不足之处。代码是赶出来的,所以会有很多地方使用不当,请大家帮我指出错误!

  • 40
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值