要求

已知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. 职责链模式,chain of responsibility

    定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这个对象连城一条链,并沿着这条链传递该请求,知道有一个对象处理它为止. 客户端并不知道哪个对象会最终处理这个请求,这样 ...

  2. ALV详解:OO SALV

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. So easy Webservice 5.WSDL 文件说明

    WSDL – WebService Description Language – Web服务描述语言 通过XML形式说明服务在什么地方-地址. 通过XML形式说明服务提供什么样的方法 – 如何调用. ...

  4. python_way day15 HTML-DAY2 HTML-DAY2、JS

    python_way day15 HTML-DAY2 html-css回顾 javascript 一.html-css回顾 1.input与+,-号的写法 <!DOCTYPE html> ...

  5. hdu 1116 Play on Words 欧拉路径+并查集

    Play on Words Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  6. Java中枚举类型简单学习

    /* * enum类型不允许继承 * 除了这一点,我们基本上可以将enum看作一个常规的类 * 我们可以添加自己的方法与属性,我们也可以覆盖其中的方法. * 不过一定要在enum实例序列的最后添加分号 ...

  7. php笔记[1]

    1:echo '$temp tires<br />'; 该代码将'$temp tires<br />'发送给浏览器,在双引号中,变量名将被变量值所替代.而在单引号中,变量名称, ...

  8. Java中ArrayList相关的5道面试题

    本文参考了 <关于ArrayList的5道面试题 > 1.ArrayList的大小是如何自动增加的? 这个问题我想曾经debug过并且查看过arraylist源码的人都有印象,它的过程是: ...

  9. iOS - UIImagePickerController

    前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UIImagePickerController : UINavigationController <NSCod ...

  10. Ubuntu Server14.04 32位安装odoo8.0简单方法

    一.wget -O - https://nightly.odoo.com/odoo.key | apt-key add - 二.echo "deb http://nightly.odoo.c ...