递归算法(一)——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; ...
随机推荐
- 构建一个简单的Maven项目
这里用Maven Archetype插件从空白开始创建简单的项目. 熟悉Maven 项目和Maven的核心概念. 关键词:构建生命周期(build lifecycle), Maven仓库(reposi ...
- So easy Webservice 8.spring整合CXF 发布WS
1.添加jar包(cxf的jar包中包含了spring的jar包),添加spring配置文件 2.web.xml中配置CXFServlet,过滤WS服务的地址 <!-- 配置CXFServlet ...
- css样式 浏览器的读取顺序
css样式 浏览器的读取顺序 例: tbody tr td{} 浏览器是先查找td,然后去找td tr,然后去找td tr tbody div p{}和div>p{}的区别 .div p{} 是 ...
- android上让我放弃使用wstring来操作中英文字符串 转
android上让我放弃使用wstring来操作中英文字符串 2013-08-07 16:37:24| 分类: cocos2d|举报|字号 订阅 项目需要,需要对中英文字符串进行遍历修改等, ...
- Jquery基本、层次选择器
基本选择器: $("#none").css("background","#bbffaa"); 改变id为none的所有元素的背景色 $(&q ...
- iOS - NSURLConnection 网络请求
前言 @interface NSURLConnection : NSObject class NSURLConnection : NSObject DEPRECATED: The NSURLConne ...
- iOS - UIDatePicker
前言 NS_CLASS_AVAILABLE_IOS(2_0) __TVOS_PROHIBITED @interface UIDatePicker : UIControl <NSCoding> ...
- [转载] linux cgroup
原文: http://coolshell.cn/articles/17049.html 感谢左耳朵耗子的精彩文章. 前面,我们介绍了Linux Namespace,但是Namespace解决的问题主要 ...
- android电池管理系统从上层的java到底层驱动的调用(转载)
1.概述 随着移动智能设备的快速发屏,电池的续航能力在很大情况下诱导了大众消费者的购买选择,android系统对电源管理的合理与否直接影响到电池的续航能力,而电池系统作为其中的一部分,主要用于对电池状 ...
- mysql批量替换数据库某字段部分内容
update 表名 set 字段名=replace(字段名,’要替换的内容’,’替换后的内容’) eg:修改scenario表中的picture字段中的ip地址. UPDATE scenario SE ...