转自于http://blog.chinaunix.net/uid-20602285-id-3078231.html
老师用ackerman函数来测试我们的lisp interpreter是否能应付extremely recursive function,虽然我们都不能,但也说明了一个健壮的interpreter是需要优化recursive function的一个道理。
ackerman函数 wiki 上有介绍:http://en.wikipedia.org/wiki/Ackerman_function
我下面记录的是怎么算出来A(4,2)。(如下表述中,ns就代表A)
ns(0,x) = x + 1
ns(1,x) = ns(0, ns(x-1)) && ns(1,0) = 2. so, ns(1,x) = x + 2
ns(2,x) = ns(1, ns(2,x-1)) = ns(2,x-1)+2 && ns(2,0) = ns(1,1) = 3. so, ns(2,x) = 2x+3
ns(3,x) = ns(2,ns(3,x-1)) = 2*ns(3,x-1)+3 && ns(3,0) = ns(2,1)=5. so, ns(3,x) = 2^(x+3) - 3
ns(4,x) = ns(3, ns(x-1)) = 2^(ns(3,x-1)+3) - 3 && ns(4,0) = ns(3,1) = 13
but if we let g(x) = ns(4,x) + 3
we have g(x) = 2^(g(x-1)) && g(0) = 16 = 2^4
so I think it's the end of this story (unless we use the symbol from knuth, which I just learned from wiki,
but I can manually get ns(4,2) = g(2) -3 = 2^(g(1)) - 3 = 2^(2^(g(0))) - 3 = 2^(2^16)) - 3 = 2^65536
- 3
these links may be helpful:
http://www.wolframalpha.com/input/?i=f%28x%29%3Df%28x-1%29%2B1%2Cf%280%29%3D2
http://www.wolframalpha.com/input/?i=f%28x%29+%3D+f%28x-1%29%2B2%2Cf%280%29%3D3
http://www.wolframalpha.com/input/?i=f%28x%29%3D2*f%28x-1%29%2B3%2Cf%280%29%3D5
http://www.wolframalpha.com/input/?i=f%28x%29%3D2^%28f%28x-1%29%2B3%29-3%2Cf%280%29%3D13
http://www.wolframalpha.com/input/?i=log2%28g%28x%29%29%3Dg%28x-1%29%2Cg%280%29%3D16
http://www.wolframalpha.com/input/?i=2^65536-3
当我算出来(4,2)后,我想尝试下得到ackerman函数的通式,结果后来尝试下后也可以了,需要引入wiki里学到的knuth发明的符号。“向上箭头符号”。↑
懂得这个符号以及扩展符号↑↑后,就可以证明ackerman函数的通式了,最傻瓜的方法是用归纳法证明,首先证明base case (1,1)成立,然后证明(1,x)成立;然后假设对于小于等于m的i或小于等于n的j (i,j)都成立,证明(i,j+1)成立。这样归纳法就完整了。
但是归纳法要求事先知道通式,这个不符合认识的流程。认识的流程应该是探索->猜想->证明。
以上我得出(4,2)的过程就是一个探索的过程。但是从中观察出规律确实很难,我也是在得到wiki的启发后知道的,接下来可以证明一下(4,x),有了knuth的符号,很容易证明;接下来再证明(5,x),也是可以的,无非knuth符号多了一层。最后再猜想,便很自然了。
ackerman函数通式的得出就写到这里。
还有一个有趣的现象,是我一个同学冷潇泠想到的,他建议把函数递归过程中的B打印出来,并且配上递归层数i,形成一些(i,B)对,把这个画在坐标系上会形成无数个抛物线,且每个抛物线都是下个抛物线的前面部分。
这个图也许还不清晰,把抛物线下的点都删掉,便有更清晰的图
这个现象还是蛮有意思的。
我的ackerman函数实现如下:
- #include <stdio.h>
- #include <stdlib.h>
-
int g = 0;
-
int ackerman(int a,
int b)
-
{
-
if(g++<100000)
{
- printf("%d %d\n",a,b);
-
}
-
else
-
exit(1);
-
if(a==0)
- return b+1;
-
else if
(b==0)
- return ackerman(a-1,1);
-
else
-
{
- return ackerman(a-1,ackerman(a,b-1));
-
}
-
}
-
int main()
-
{
-
int a,b;
- scanf("%d %d",&a,&b);
- ackerman(a,b);
- }
产生数据后分析数据的perl脚本如下:
- #!/usr/bin/perl
- open(INP,"ackerman4.2.txt");
- open(OUT,">localm1");
- $a=0;
- $b=0;
- $c=0;
- $i=0;
- while(defined($line=<INP>))
-
{
- @col=split(" ",$line);
- $a=$col[1];
#the 2nd column.
B
- if(($a<$b)&&($b>$c))
-
{
- #print OUT "$i ${col[0]} $b \n";
- print OUT "$i $b \n";
- #print OUT "$i $b \n";
-
}
- $c=$b;
- $b=$a; #b
= a.
b is the temporary max
- $i++;
-
}
- close(INP);
- close(OUT);
然后用gnuplot
>plot 'localm1'
即可得出图片。
图片效果由于我不熟悉gnuplot便用得最原始的。
最后引用冷潇泠画的一个图,这个图更清晰。也是gnuplot。也可以用excel画。我都只知道理论上可画,但实际上都没经验。
分享到:
相关推荐
这种实现对于理解和学习递归、动态规划以及函数计算的效率有重要的价值。在实际编程中,这样的优化技术也被广泛应用于其他递归函数,特别是那些具有相同子问题的函数,例如斐波那契数列或最短路径计算。
本篇文章将深入探讨Ackerman函数的基本概念、特性以及其在C++中的具体实现。 #### Ackerman函数的概念与特性 Ackerman函数由德国数学家Wilhelm Ackermann于1928年首次提出,是递归函数理论的一个经典案例。它被...
Ackerman 函数是一种著名的递归计算函数,常用于探讨计算复杂性和递归理论。它以数学家 Moses J. Ackerman 的名字命名,其定义为一个三元运算符,通常写作 A(m, n),其中 m 和 n 是非负整数。 Ackerman 函数的计算...
Ackerman函数,通常被称作阿克曼函数,是一个非递归定义的多变量阶乘类函数,由美国数学家Maurice Karnaugh在1962年提出,但以计算机科学家Morse和Ackerman的名字命名。这个函数在计算理论和算法设计中常被用作一个...
本文将深入探讨 Ackerman 函数的两种非递归实现方法:数组递推和栈消除递归,并通过源代码分析它们的工作原理。 1. Ackerman 函数定义: Ackerman 函数通常表示为 A(m, n),其中 m 和 n 是非负整数。它的定义如下:...
算法学习过程中学习的Ackerman函数,C++代码,Main函数
Ackerman函数,通常被用来作为一个展示递归深度和复杂性的例子。它是一个多变量的、非线性的递归函数,由数学家Morton Ackerman在20世纪30年代提出。这个函数以其非平凡的递归结构和极端的快速增长而闻名。 首先,...
通过以上分析,我们可以看到,阿克曼函数的非递归实现主要涉及堆栈操作、递归转换以及对计算复杂性的理解。这个话题对于学习数据结构和算法的学生来说,是一个挑战性的实践项目,有助于提升他们的编程技能和对复杂...
总结,阿克曼函数的递归和非递归实现都是理解递归、堆栈以及数据结构在计算复杂性中的作用的重要案例。非递归实现通过堆栈有效地避免了递归调用的限制,展示了如何用迭代方法解决原本看似需要递归的问题。
数据机构的晦涩难懂我有亲身经历,所以提供一些算法来帮助大家!
Ackerman递归函数int ack(int m,int n)
Ackermann 函数是一种著名的递归函数,用于展示非平凡的递归行为。它是由荷兰数学家马里乌斯·阿克曼在1928年提出的。该函数定义如下: 1. ACK(0, n) = n + 1 2. ACK(m, 0) = ACK(m-1, 1) 3. ACK(m, n) = ACK(m-1, ...
通过比较这两个程序,你可以看到递归和非递归算法在实现上的差异,以及它们在处理复杂递归问题时的不同策略。 理解并分析这两个程序,可以帮助你深入学习C语言编程,特别是递归和栈的概念。同时,这也为理解递归...
`ackerman_ros_robot_gazebo_simulation-master`这个文件夹很可能是项目的源代码仓库,其中可能包含C++或Python的ROS节点代码,配置文件,Gazebo世界模型,以及启动脚本等,这些都支持上述功能的实现。 通过学习和...
`ackerman` 函数实现了阿克曼函数的递归定义。它包含三个基本情况: 1. 当 \(n = 0\) 时,返回 \(m + 1\)。 2. 当 \(m = 0\) 且 \(n > 0\) 时,返回 \(A(n-1, 1)\)。 3. 对于其他情况,即 \(n > 0\) 且 \(m > 0\) 时...
Ackerman非递算法,全称为阿克曼函数,是计算机科学中一个著名的非递归定义的函数,由美国数学家Maurice Karnaugh在1934年提出,但以计算机科学家Morse和Godel的学生Gunter Ackerman的名字命名。这个函数主要用于...
Ackerman 函数是一种非常特殊的数学函数,它在计算复杂度理论和计算机科学中被用作一个例子,展示了非平凡的递归函数行为。这个函数以其创造者 Moses Ackerman 的名字命名,它不是普通的算术或组合函数,而是具有...
在本篇文章中,我们将会探讨Python中的递归函数和二分查找算法,以及它们在实际问题中的应用。递归是一种强大的编程技术,它允许函数调用自身。二分查找算法是一种高效的搜索技术,适用于有序列表,通过反复将搜索...
由数学家 Willhelm Ackermann 开发的 Ackerman 函数以其极快的增长速度令人印象深刻,并具有更多迷人的功能。 有了这个简单的代码,Ackermann 函数就可以在 Matlab 中轻松使用。