要求

已知akm函数如下:

{ n+1 while m=0 }                          => Rule I

akm(m,n)= { akm(m-1,1) while n=0 }                => Rule II

{ akm(m-1,akm(m,n-1)) otherwise } => Rule III

写出递归与非递归算法,并输出调用过程。

实现

参见https://github.com/bajdcc/ALGImplements/blob/master/akm/akm.cpp

#include "stdafx.h"
#include <stdio.h>
#include <stack> /*
* Ackerman function definition
*
* { n+1 while m=0 } => Rule I
* akm(m,n)= { akm(m-1,1) while n=0 } => Rule II
* { akm(m-1,akm(m,n-1)) otherwise } => Rule III
*/ //************************************
// Method: akm1
// FullName: 递归解法
// Access: public
// Returns: int
// Qualifier: recursion
// Parameter: int m
// Parameter: int n
//************************************
int akm1(int m, int n)
{
printf("Compute akm(%d,%d)\n", m, n);
if (m == )
{
printf("Compute akm(%d,%d) - val = %d\n", m, n, n + );
return n + ;
}
else if (n == )
{
return akm1(m - , );
}
else
{
return akm1(m - , akm1(m, n - ));
}
} //************************************
// Method: akm2
// FullName: 非递归解法一
// Access: public
// Returns: int
// Qualifier: non-recursion
// Parameter: int m
// Parameter: int n
//************************************
int akm2(int m, int n)
{
/* 这个解法有其特殊性,因为递归调用数为一,没有并列调用(一个以上参数为递归调用,如akm(akm(...),akm(...))) */
//这样,在栈中,调用关系为线性关系,而不是树形关系 //栈的惰性求值方法,若表达式中含有非求值akm函数,则记录它在链表中的位置
//由于存在m和n参数以及akm函数返回值,因此一个结点中有m,n,val
struct akm_node
{
int m, n, val;
};
std::stack<akm_node> exp_stack;
akm_node initial_val;//初始值
initial_val.m = m;
initial_val.n = n;
initial_val.val = -;//返回值尚未求得
exp_stack.push(initial_val);
/* 注意:这个方法假设akm的值为正数 */
while (true)//主循环
{
akm_node& node = exp_stack.top();//当前处理的表达式,取栈顶且不出栈,取引用说明要修改
printf("Compute akm(%d,%d)\n", node.m, node.n);
//为什么为top不急着出栈,这是因为之前的表达式要用到当前值
//此时出栈后,之前的式子就没有获得返回值
//出栈的最佳时机,即为式子取得其参数(返回值)后
if (node.val != -)//值被求出
{
//什么时候才是出栈的时机,这个时候!
//此时,值已经求得,即为可解问题
//我们知道可解问题一般为树的叶子结点
//求得这个值之后,可能这个结果是上一次调用的参数
//那么应该亡羊补牢,赶紧补上上一次调用的参数
exp_stack.pop();//值在node中,故可出栈
if (exp_stack.empty())//Rule I
{
//假使当前栈空,那么这个node就是最终值(所有嵌套全部计算完毕),九九归一
return node.val;
}
else
{
//栈不空,说明【肯定】含有待解问题
//因为当且仅当栈空时,调用栈为空,即树归约到根结点,得到最终结果
akm_node& not_computed_exp = exp_stack.top();//取引用说明要修改
if (not_computed_exp.n == )//Rule II called Rule I
{
not_computed_exp.val = node.val;//give it computed value
}
else if (not_computed_exp.n == -)//Rule III called Rule I
{
not_computed_exp.n = node.val;
}
else
{
not_computed_exp.val = node.val;
}
}
continue;
}
if (node.m == )//Rule I: m+1 while m equals to zero
{
printf("Compute akm(%d,%d) - val = %d\n", node.m, node.n, node.n + );
node.val = node.n + ;
}
else if (node.n == )//Rule II akm(m-1,1) while n equals to zero
{
//此时值不可直接求解,故需要嵌套求值(惰性求值)
//将二次调用参数进栈
akm_node secondary_call_exp;
secondary_call_exp.m = node.m - ;
secondary_call_exp.n = ;
secondary_call_exp.val = -;
exp_stack.push(secondary_call_exp);
}
else//Rule III akm(m-1,akm(m,n-1)) otherwise
{
//此时值不可直接求解,故需要嵌套求值(惰性求值)
akm_node secondary_call_exp;//二次调用
secondary_call_exp.m = node.m - ;
secondary_call_exp.n = -;//-1代表未知
secondary_call_exp.val = -;
exp_stack.push(secondary_call_exp);
akm_node tertiary_call_exp;//三次调用
tertiary_call_exp.m = node.m;
tertiary_call_exp.n = node.n - ;
tertiary_call_exp.val = -;
exp_stack.push(tertiary_call_exp);
continue;
}
}
return ;
} int main()
{
printf("============ 递归 ===========\n");
printf("akm(2,1)=%d\n", akm1(, ));
printf("\n");
printf("============ 非递归 ===========\n");
printf("akm(2,1)=%d\n", akm2(, ));
printf("\n");
return ;
}

递归算法(一)——akm的更多相关文章

  1. 金山云笔试题:AKM函数

    1. 题目描述 /** 阿克曼(Ackmann)函数 [题目描述] 阿克曼(Ackmann)函数A(m,n)中,m,n定义域是非负整数(m<=3,n<=10),函数值定义为: akm(m, ...

  2. 递归算法经典实例小结(C#实现)

     一 .递归算法简介 在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法. 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往 ...

  3. 转: JAVA递归算法实例小结

    一.递归算法设计的基本思想是: 对于一个复杂的问题,把原问题分解为若干个相对简单类同的子问题,继续下去直到子问题简单到能够直接求解,也就是说到了递推的出口,这样原问题就有递推得解. 在做递归算法的时候 ...

  4. xml 读取递归算法

    xml 读取递归算法:

  5. 后台返回字符串类型function的处理 (递归算法)

    $(function(){ $.ajax({ type: "post", url: "${ctx}/modules/fos/reference/echart", ...

  6. JAVA递归算法

    1.什么是递归算法 递归算法就是直接或间接调用自己的算法 2.问题1:一列数的规则如下: 1.1.2.3.5.8.13.21.34 ,求第30位数是多少?使用递归实现 public class Fib ...

  7. 【Tree 1】树形结构数据呈现的递归算法实现

    一.基本概况 在我的项目中,常常会用到树形结构的数据,最为明显的就是左边菜单栏,类似于window folder一样的东西. 而我之前一直是借助前端封装好的ZTree等工具实现展示,而后台则通常使用递 ...

  8. N个数全排列的非递归算法

    //N个数全排列的非递归算法 #include"stdio.h" void swap(int &a, int &b) { int temp; temp = a; a ...

  9. C# 递归算法与冒泡

    C# 递归算法求 1,1,2,3,5,8,13···static void Main(string[] args){ int[] cSum = new int[10];for (int i = 0; ...

随机推荐

  1. JAVA开发--[二维码名片生成系统]

    上个月学校有个软件创新杯,最近看了网上很火的二维码比较不错.参考了国内国外一些技术文章,发现国外的确实好很多. 用的是QRcode包来实现的,基本常见的功能全部实现了. 因为刚学2个月,部分做得不是很 ...

  2. poj 1654 Area (多边形求面积)

    链接:http://poj.org/problem?id=1654 Area Time Limit: 1000MS   Memory Limit: 10000K Total Submissions:  ...

  3. c++ string的实现。

    第三次做了.只是做个复习.偶然发现之前的版本有内存泄露.基本功还是不过关.这次应该没有内存泄漏了.虽然是个简单版本. 1)了解堆,栈,值copy. 2)几个常用的c的字符函数和c中的char 如何表示 ...

  4. mysq错误(1)空用户创建库

    mysql5.6.24免安装版: 1.ERROR 1044 (42000): Access denied for user ''@'localhost' to database 现象:创建库失败. 出 ...

  5. 文件MD5校验

    1. 以前记得是在 msdn.itellyou.cn 上下载的 MD5 校验工具,应该是 IHasher,但是现在 msdn.itellyou.cn 上搜不到这个工具了... 2.

  6. EF中使用SQL语句或存储过程(小笔记)

    1.无参数查询 var model = db.Database.SqlQuery<UserInfo>("select* from UserInfoes ").ToLis ...

  7. 2014 Multi-University Training Contest 1

    A hdu4861 打表找规律 #include <iostream> #include<cstdio> #include<cstring> #include< ...

  8. php三维数组变二维数组

    <?php $result = Array(0 => Array(0 => Array(bid => 41,brealname => 'we教官',cid => 4 ...

  9. mysql 命令行快速导出数据,导入数据

    如果数据有20几万以上的时候,下面的方法很实用 导出数据 1.into outfile select * from table into outfile 'C:/a.sql'; 2.mysqldump ...

  10. 数据分析学习(zhuan)

    http://www.zhihu.com/question/22119753 http://www.zhihu.com/question/20757000 ********************** ...