此文记录阿克曼函数的递归和非递归的实现,以及我对阿卡曼函数的认识。

阿克曼函数定义

Ackermann(m,n)函数定义如下:
Ackermann(0,n) = n+1;
Ackermann(m,0) = Ackermann(m-1,1);
Ackermann(m,n) = Ackermann(m-1,Ackermann(m,n-1)),m>0,n>0。

递归实现

思路:递归实现就很简单了,因为给出了表达式,确定边界m==0后,直接往上套。
代码:

    public static long solve_rec(long m,long n){if(m == 0){return n+1;}else if(m > 0 && n == 0){return solve_rec(m-1,1);}else{return solve_rec(m-1,solve_rec(m,n-1));}}

非递归实现

思路:用栈来模拟递归实现阿克曼函数求解。先往栈中放入需要求解的ack(m,n),判断m,n的状态来进行pop和push。说的很模糊,详情见代码。(思路来自该博客:https://blog.csdn.net/xiaofei_it/article/details/51524754)
举例:以计算Ackermann(2,1)为例,结合代码食用更加,ack为一个类,见后面详细代码。(关于图中的res可以没有描述清楚,以栈顶的res为每次操作的结果)

代码:

    //思路:使用栈来模拟递归函数public static long solve(long m,long n){Stack<Ack> stack = new Stack<>();stack.push(new Ack(m,n));   //放入要求解的ack//res用来记录ack(0,n)的值//如果res大于0,则说明当前的函数层层调用(push)已经到底了,开始pop了。long res = -1;while(!stack.empty()){Ack ack = stack.peek(); //对栈顶的ack进行分析if(ack.m == 0){         //m为0,则求解出ack(0,n)的结果赋给res,并移出stackres = ack.n+1;stack.pop();}else if(ack.n == 0 && ack.m > 0){if(res < 0) {stack.push(new Ack(ack.m-1,1)); //res小于0,Ackermann(m,0) = Ackermann(m-1,1);}else {stack.pop();    //res大于0,则说明已经计算过了,可以pop}}else{if(ack.data < 0){   //还没有赋值,只有维if(res < 0){stack.push(new Ack(ack.m,ack.n-1)); //计算Ackermann(m,n)所需要的Ackermann(m,n-1)}else {ack.data = res; //设置data是为了判断是否被计算res = -1;       //重置为1stack.push(new Ack(ack.m-1,ack.data));//Ackermann(m,n) = Ackermann(m-1,Ackermann(m,n-1)),这里的Ackermann(m,n-1)为data}}else{stack.pop();    //已经计算出来的ack值被用到了,所以就pop出来}}}return res;}

详细代码

import java.util.Stack;public class Ackermann{public static void main(String[] args) {System.out.println(solve(2,1));System.out.println(solve_rec(2,1));}//思路:递归方法public static long solve_rec(long m,long n){if(m == 0){return n+1;}else if(m > 0 && n == 0){return solve_rec(m-1,1);}else{return solve_rec(m-1,solve_rec(m,n-1));}}//思路:使用栈来模拟递归函数。有点难理解public static long solve(long m,long n){Stack<Ack> stack = new Stack<>();stack.push(new Ack(m,n));   //放入要求解的ack//res用来记录ack(0,n)的值//如果res大于0,则说明当前的函数层层调用(push)已经到底了,开始pop了。long res = -1;while(!stack.empty()){Ack ack = stack.peek(); //对栈顶的ack进行分析if(ack.m == 0){         //m为0,则求解出ack(0,n)的结果赋给res,并移出stackres = ack.n+1;stack.pop();}else if(ack.n == 0 && ack.m > 0){if(res < 0) {stack.push(new Ack(ack.m-1,1)); //res小于0,Ackermann(m,0) = Ackermann(m-1,1);}else {stack.pop();    //res大于0,则说明已经计算过了,可以pop}}else{if(ack.data < 0){   //还没有赋值,只有维if(res < 0){stack.push(new Ack(ack.m,ack.n-1)); //计算Ackermann(m,n)所需要的Ackermann(m,n-1)}else {ack.data = res; //设置data是为了判断是否被计算res = -1;       //重置为1stack.push(new Ack(ack.m-1,ack.data));//Ackermann(m,n) = Ackermann(m-1,Ackermann(m,n-1)),这里的Ackermann(m,n-1)为data}}else{stack.pop();    //已经计算出来的ack值被用到了,所以就pop出来}}}return res;}}class Ack{public long m;public long n;public long data;public Ack(long m, long n) {this.m = m;this.n = n;this.data = -1;}
}

扯淡

做这道算法题时,题目很简陋(就一个ack函数,且没有给出范围!!!),并不知道这是阿克曼函数,以前也没有听闻过(比较孤陋寡闻。。。)。有趣的就是,当我写好这个递归代码时,我随便用了(5,3)作为例子来跑一下。等了一下说是栈溢出,我就感觉可能是代码哪个地方写错了。我就测试了一下(2,1)和(2,5)两个例子发现没有问题。然后我就随便在一个地方加上了一个print,发现一直在循环,这就让我怀疑是不是代码写错了(因为我不是print中间的结果),我又检查了一遍逻辑发现没有错误啊。
然后我就百度了一下,才发现这是阿克曼函数,百度百科给出的一句话“阿克曼函数它的输出值增长速度非常快,仅是对于(4,3)的输出已大得不能准确计算。”当时我就震惊了(内心os:啥叫大的不能计算。我也没看出它有这么大),然后看到关于阿卡曼函数的科普,给我的感觉就是,真tm大。大概有这么大:
Ackermann( 0 , n ) = n + 1
Ackermann ( 1 , n ) = n + 2
Ackermann ( 2 , n ) = 2n + 3
Ackermann ( 3 , n ) = 2^(3+n) - 3
Ackermann ( 4 , 0 ) = 2^4 - 3
Ackermann ( 4 , 1 ) = 2 ^ (2 ^ 4) - 3 = 2^16 -3
Ackermann ( 4 , 2 ) = 2^ (2^ (2^ 4)) - 3 = 2^65536 - 3

要知道java中的long类型最大值也就2^64-1。
我不禁回想起斐波拉契数列的第5000项也不过1000多位数(计算Fibonacci的第5000项),而Ackermann(4,2)就有19729位数。两者完全不是一个数量级的。我还企图计算Ackermann(5,3),算它几个世纪未必算出来。还是要多读书多看报才能避免自己的无知。¬_¬

阿克曼函数实现(Java代码)相关推荐

  1. 2.1.1 Java代码基本格式

    任何语言都有属于自己的语法规则,Java也一样,一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作,Java还是一种强类型的语法严谨的语言,接下来我们来看看Java ...

  2. Android Studio编写运行测试纯java代码可带main()函数

    问题 小伙伴们在做安卓项目的时候,是不是有时候会忘记某些api的使用方法,不太确定他们的结果是怎样的,需要写一些测试代码,验证看看我们的写法是否正确.刚开始的时候我是在页面上写一个Button,添加点 ...

  3. java main函数_一行JAVA代码如何运行起来?

    在程序员的世界中,你总会听到一句"PHP是世界上最好的语言"的调侃.然而在你进入软件程序开发之后,你会发现即使开发语言千千万,最盛行的还是JAVA.从淘宝的技术变迁中我们可以见一些 ...

  4. PMT函数(5个参数)使用java代码实现

    WPS中的PMT函数(5个参数)使用java代码实现 此篇文章中基本可以满足全部需要PMT函数的全部需求. PMT(Rate, Nper, Pv, Fv, Type).PMT函数百度介绍 语法参数 ● ...

  5. Java代码实现—函数递归

    目录 1.前言 2.什么是递归 2.1 一则故事 2.2 递归的概念 2.3 递归策略 2.4 递归的两个必要条件 3.递归代码举例 3.1 n的阶乘(递归实现) 3.2 数字之和 3.3 斐波那契数 ...

  6. Java实现min函数_AcWing 41. 包含min函数的栈--Java代码

    题目描述 blablabla 样例 blablabla 算法1 (辅助栈,同时压栈) $O(n)$ 分三种方法 1.(基础)x入栈,然后辅助栈的栈顶和x比较,x小,将x压入辅助栈,栈顶小,将栈顶压入 ...

  7. 语言阿克曼函数_函数式的动态规划

    函数式的动态规划 动态规划是一类很常用的算法,在C/C++/Java中一般使用于数组进行记忆化.而函数式编程语言一般无法方便地操作数组这些依赖副作用的数据结构,函数式的记忆化便要另寻他法. 本文就是一 ...

  8. 数据结构笔记--二叉查找树概述以及java代码实现

    一些概念: 二叉查找树的重要性质:对于树中的每一个节点X,它的左子树任一节点的值均小于X,右子树上任意节点的值均大于X. 二叉查找树是java的TreeSet和TreeMap类实现的基础. 由于树的递 ...

  9. asp java 变量_ASP_用stack变量优化Java代码,  java程序包含了大量的对象 - phpStudy...

    用stack变量优化Java代码 java程序包含了大量的对象,我们需要了解它们是从哪里被访问的,变量存储于何处对程序的性能有显著的影响--尤其是某些需要被频繁访问的变量. 我们写一个Java类,在其 ...

  10. 避免在JSP中写java代码

    作者:蜗牛学院CTO李懿老师 ​自从十年前的taglibs(如JSTL)和EL(表达语言,这些事情)诞生以来,在JSP中使用scriptlet(<% %>这些东西)的确是非常不鼓励的. 小 ...

最新文章

  1. Socket网络协议之二
  2. android 文件名 标题,有什么方法可以让Android的默认浏览器识别Content-Disposition:attachment下载中的非ASCII文件名?...
  3. 领计算机二级证材料,计算机二级证书怎么领
  4. linux彻底卸载multipath,深度分析LINUX环境下如何配置multipath
  5. 计算机系统高级设置在哪里,Win7系统高级设置在哪里
  6. IDEA Maven 聚合项目(多模块)搭建--最精简
  7. c语言制作贪吃小白入门,小白入门——easyx界面版“贪吃蛇”的C语言实现(详细)...
  8. Atitit 业务领域体系分类 目录 1. 按照互联网企业类型以及只是体系类的分类 2 2. 电子商务 2 3. **通信类社交 Im类 em 2 4. **信息搜索类爬虫 2 4.1. 媒体
  9. zookeeper 可以干什么
  10. Ubuntu卸载历程,包含重启进入grub解决方案
  11. 相对论【6】广义相对论简单的几乎无关的讨论
  12. HBase常用过滤器
  13. 怎么登陆163邮箱?163的邮箱有哪些实用技巧?
  14. 盛世昊通全新升级,引领智慧新经济
  15. 网络命令——traceroute、tracert(windows)
  16. CVE-2018-2628漏洞复现
  17. Google分析统计
  18. 日常工作--定位查看服务器日志笔记
  19. MemCache 部署以及介绍 ;
  20. Typora快捷键:

热门文章

  1. 微信小程序支付宝小程序合并二维码
  2. OCR文本扫描 轮廓检测 透视变换-唐宇迪笔记
  3. c语言有趣代码,实用有趣的C语言程序
  4. 查看计算机桌面隐藏文件夹,电脑怎么查看隐藏文件(隐藏文件夹显示方法)
  5. 项目测试日报模板整理
  6. 创建数据库常用SQL语句
  7. 斗鱼弹幕服务器第三方接入协议v1.6.2,GitHub - yyc-dev/douyu-sdk: DouYu-SDK,一个基于斗鱼弹幕API封装的SDK...
  8. 怎样正确做 Web 应用的压力测试?
  9. vivado linux使用教程,Vivado2017.4下载|Xilinx Vivado 2017.4 最新版(含使用教程)下载...
  10. stata15中文乱码_Stata14打开13数据乱码处理办法