递归算法(一)——akm
要求
已知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的更多相关文章
- 金山云笔试题:AKM函数
1. 题目描述 /** 阿克曼(Ackmann)函数 [题目描述] 阿克曼(Ackmann)函数A(m,n)中,m,n定义域是非负整数(m<=3,n<=10),函数值定义为: akm(m, ...
- 递归算法经典实例小结(C#实现)
一 .递归算法简介 在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法. 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往 ...
- 转: JAVA递归算法实例小结
一.递归算法设计的基本思想是: 对于一个复杂的问题,把原问题分解为若干个相对简单类同的子问题,继续下去直到子问题简单到能够直接求解,也就是说到了递推的出口,这样原问题就有递推得解. 在做递归算法的时候 ...
- xml 读取递归算法
xml 读取递归算法:
- 后台返回字符串类型function的处理 (递归算法)
$(function(){ $.ajax({ type: "post", url: "${ctx}/modules/fos/reference/echart", ...
- JAVA递归算法
1.什么是递归算法 递归算法就是直接或间接调用自己的算法 2.问题1:一列数的规则如下: 1.1.2.3.5.8.13.21.34 ,求第30位数是多少?使用递归实现 public class Fib ...
- 【Tree 1】树形结构数据呈现的递归算法实现
一.基本概况 在我的项目中,常常会用到树形结构的数据,最为明显的就是左边菜单栏,类似于window folder一样的东西. 而我之前一直是借助前端封装好的ZTree等工具实现展示,而后台则通常使用递 ...
- N个数全排列的非递归算法
//N个数全排列的非递归算法 #include"stdio.h" void swap(int &a, int &b) { int temp; temp = a; a ...
- C# 递归算法与冒泡
C# 递归算法求 1,1,2,3,5,8,13···static void Main(string[] args){ int[] cSum = new int[10];for (int i = 0; ...
随机推荐
- vsftpd配置参数详细整理
vsftpd配置参数详细整理 -|白王斧三又干一 vsftpd配置参数详细整理 -|白王斧三又干一 发表于 2005-10-23 20:30:00 1.vsftpd配置参数详细整理#接受 ...
- Web开发——Tomcat的配置
1.选择Tomcat 1.Apache官网http://apache.org/ 2.Tomcat官网http://tomcat.apache.org/ 3.Tomcat下载地址http://tomca ...
- hdu 2112 (最短路+map)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2112 HDU Today Time Limit: 15000/5000 MS (Java/Others) ...
- day20 FORM补充(随时更新),F/Q操作,model之多对多,django中间件,缓存,信号
python-day20 1.FROM生成select标签的数据应该来源于数据库. 2.model 操作 F/Q (组合查询) 3.model 多对多操作. 4.中间件 :在请求到达url前先会经过 ...
- SQL 语句转换格式函数Cast、Convert
CAST和CONVERT都经常被使用.特别提取出来作为一篇文章,方便查找. CAST.CONVERT都可以执行数据类型转换.在大部分情况下,两者执行同样的功能,不同的是CONVERT还提供一些特别的日 ...
- Sql 行转列问题总结
行转列问题总结 1.行转列 ---1.最简单的行转列/* 问题:假设有张学生成绩表(tb)如下:姓名 课程 分数张三 语文 74张三 数学 83张三 物理 93李四 语文 74李四 数学 84李四 物 ...
- HttpServletRequest学习
package cn.request; import java.io.IOException; import java.io.PrintWriter; import java.io.Unsupport ...
- iOS - OC RunTime 运行时
1.运行时的使用 向分类中添加属性 // 包含运行时头文件 #import <objc/runtime.h> /* void objc_setAssociatedObject(id obj ...
- 播放列表文件用于HTTP实时流的使用
广告播放清单(Discontinuities): 通常你会想要提供一系列的电影,在每个电影前面显示一些品牌(广告),让用户知道这些电影来自你的特定网站.一种方法是简单地将广告与每部电影合并.但是如果你 ...
- linux学习笔记2-命令总结1
计划一个长期过程系统学习linux,这是本周学习总结,如果错误望指出纠正. 文件处理命令 命令格式与目录处理命令 ls 目录处理命令 cd cp mkdir mv pwd rm rmd ...