第一次写博客,初学数据结构,以下是我对阿克曼函数非递归实现的一点拙见,有错误的地方,欢迎大家批评指教。

1.初识阿克曼函数

我们先来看看阿克曼函数的形式

已知Ackerman函数的定义如下:

n+1 m=0

akm(m, n) = akm(m-1, 1) m≠0,n=0

akm(m-1, akm(m, n-1) m≠0,n≠0

阿克曼函数是以递归的形式给出的,采用递归算法解决这个问题是很直接的

//Ackerman 递归实现算法

ElemTypy Ackerman(ElemType m,ElemType n)

{//输入m,n的值,返回函数结果值

if(m == 0) result = n+1;

else if(m != 0 && n == 0) result = Ackerman(m-1,1);

else result = Ackerman((m-1,Ackerman(m,n-1)));

return result;

}//Ackerman

2.阿克曼函数的非递归实现

我认为,要想完成阿克曼函数的非递归实现,有三点十分重要。

①.要清楚阿克曼函数的递归算法,本质上是是如何实现的,了解之后我们发现,递归的本质,是用系统的栈存储了递归过程产生的地址和变量。

②.了解到递归的本质之后,我们就可以设想,自己建立一个栈,手动(用自定义函数) 来实现入栈和出栈操作。

③.当我们想到用自己建立的栈去实现非递归时,紧接着的问题就是,用这个栈去存储什么内容? 要想解决这个问题,我们需要仔细研究阿克曼函数本身,研究之后,我们发现,函数的出口,在“m = 0”时,输出的是值“n+1”,我觉得看到这一点对于理解下面的非递归实现代码非常重要。

我们还可以发现,输入一个m,n,要求得函数值,不过是m,n不停地变化,不停地带入,一层一层求解,最终再返回到我们要求的问题的过程,于是建立两个存储m,n的值的栈的思想就萌生了。

我们来重点理解一下非递归实现的算法:

int Ackerman(int m,int n) /函数的返回值是整型,也就是 我们前面提到的出口“n+1”的值/

{

STACK S,T; //建立两个栈S,T,分别用来存储m,n的值

S = InitStack();

T = InitStack();

Push(&S,m);

Push(&T,n); /将输入的m,n值压入栈,怎么更好的理解把这两个数压入栈到底是什么意思呢? 我的理解是,把这两个数压入栈就像是向输入计算机输入你要求的问题,计算机把这两个数存起来,然后按照程序执行,如果可以得到结果(比如m=0的情形),那就回答你的问题,并且清除你输入的参数,如果不能直接解决,那就先保留这两个数,然后走到下一步程序,看能不能解决,如果能解决,那就返回结果给上一层,如果不能保留,就继续往下走,问题走到尽头的时候,一定会得到解决,再一层一层得返回结果,最终求得问题的答案/

while(StackEmpty(&S)) /当栈不为空时,进行循环/

{

while(m != 0)

{

if(n == 0)

{ //m!=0 && n == 0 的情况

m = m-1;

n = 1;

Push(&S,m);

Push(&T,n); /将改变后的m,n值压入栈/

}

else

{

n = n-1;

Push(&S,m-1);

Push(&T,-1); /这一步是m,n都不为0的情况,非常特殊,因为这一步是一个双递归的过程,我们要向走通这一步,就要先解决最内层的递归,然后再解决外层递归,为此,我们将m-1压入S栈,-1压入T栈,-1是一个标志,用来标识这种特殊情况。 我们还发现,这一步我们把n复制为n-1,但是没有对m重新赋值,这也是为了要求先求出内层递归的值akm(m, n-1),当求出这个值之后,我们用求得的值赋把T栈中该位置的-1替换掉,就成功走通这一步啦!/

}

}

n = n+1; /当m等于0时,按照函数法则执行,给n赋值n+1/

while(StackEmpty(&S) && *(T.top-1) != -1)

{

Pop(&S);

Pop(&T);

}/这一步可以和我上面提到的情况特殊那一步联系起来,当你最终求得akm(m, n-1)时(其实也就是求得的T栈中-1位置本应该压入的n的值),我们的目的达到了,就可以把S,T栈中没用的信息全都弹出,回到我们要解决的问题的位置/

if(StackEmpty(&S))

{

m = *(S.top-1);

Pop(&T);

Push(&T,n);

}/但我们回到了我们要解决的问题的位置(把-1压入栈的位置),由于我们再计算内层递归的时候,改变了m的值,这里我们把m赋值为我们之前把-1压入T栈的同时,压入S栈的“m-1”,也就是此时S栈的栈顶元素/

}

return n; /*当整个循环完成时,返回n的值,就是我们想要的最终答案*/

}

3.以(2,1)为例,栈的变化图解

第一次发博客,有错误的地方希望大家多多指教

阿克曼函数的c语言,C语言,关于阿克曼函数非递归实现的一点拙见相关推荐

  1. c语言归并排序数组不固定,归并排序非递归实现C语言

    话说这个东西写到凌晨3点27分,都没有写好.刚才睡醒了写完的.主要遇到的问题就是当数组大小不是2的幂的时候发生的 right_end 越界的时候.我的逻辑起初偏于复杂,后来重新组织逻辑,当发生 rig ...

  2. c语言 二叉树先序遍历(非递归)

    /*************************** * author:vivi * date: 19-09-10 ****************************/ #include & ...

  3. C语言中连续调用rand函数,返回值不变

    C语言中连续调用rand函数,返回值不变 最近用C语言随机函数编程发现了一个奇怪的现象: 简易版代码: #include<stdio.h> #include<stdlib.h> ...

  4. ACMNO.41C语言-数字调序 有n个整数,使前面各数顺序向后移m个位置,最后m个数变成前面m个数,见图。写一函数:实现以上功能,在主函数中输入n个数和输出调整后的n个数

    题目描述 有n个整数,使前面各数顺序向后移m个位置,最后m个数变成前面m个数,见图. 写一函数:实现以上功能,在主函数中输入n个数和输出调整后的n个数. 输入 输入数据的个数n n个整数 移动的位置m ...

  5. R语言使用randomForest包构建随机森林模型(Random forests)、使用importance函数查看特征重要度、使用table函数计算混淆矩阵评估分类模型性能、包外错误估计OOB

    R语言使用randomForest包中的randomForest函数构建随机森林模型(Random forests).使用importance函数查看特征重要度.使用table函数计算混淆矩阵评估分类 ...

  6. R语言使用ggplot2包geom_jitter()函数绘制分组(strip plot,一维散点图)带状图(添加箱图、带缺口的小提琴图、小提琴图)实战

    R语言使用ggplot2包geom_jitter()函数绘制分组(strip plot,一维散点图)带状图(添加箱图.带缺口的小提琴图.小提琴图)实战 目录 R语言使用ggplot2包geom_jit ...

  7. R语言可视化、编写自定义函数可视化水平排序条形图(horizontal bar plot)、自定义图像布局模仿经济学人杂志可视化效果、右侧添加标签数值图像方框、自定义背景色、水平条形图中间线条等

    R语言可视化.编写自定义函数可视化水平排序条形图(horizontal bar plot).自定义图像布局模仿经济学人杂志可视化效果.右侧添加标签数值图像方框.自定义背景色.水平条形图中间线条.网格线 ...

  8. R语言广义线性模型函数GLM、广义线性模型(Generalized linear models)、GLM函数的语法形式、glm模型常用函数、常用连接函数、逻辑回归、泊松回归、系数解读、过散度分析

    R语言广义线性模型函数GLM.广义线性模型(Generalized linear models).GLM函数的语法形式.glm模型常用函数.常用连接函数.逻辑回归.泊松回归.系数解读.过散度分析 目录

  9. R语言使用fs包的file_info函数查看文件元信息(属性信息)、使用file_chmod函数修改文件的权限、使用file_chown函数修改文件的所有者

    R语言使用fs包的file_info函数查看文件元信息(属性信息).使用file_chmod函数修改文件的权限.使用file_chown函数修改文件的所有者 目录

  10. R语言编写自定义描述统计计算函数、使用doBy包的summaryBy函数计算不同分组(group)的描述性统计值(Descriptive statistics by group、样本个数、均值、标准)

    R语言编写自定义描述统计计算函数.使用doBy包的summaryBy函数计算不同分组(group)的描述性统计值(Descriptive statistics by group using summa ...

最新文章

  1. mysql集群的配置
  2. linux   vim配置,打造ide
  3. vc下c语言网络编程,用VC编写C/S消息传送程序
  4. Mysql安装两种方法
  5. mysql运维管理-mysqldump 备份与恢复数据库20
  6. SPOJ GSS2 Can you answer these queries II (线段树离线) - xgtao -
  7. winform 分页控件分享(二)
  8. CSS基础「三」盒子模型/产品模块案例/圆角边框/盒子阴影/文字阴影
  9. 2如何识别操作系统_扫描车牌识别车牌号的功能sdk
  10. 亚信安全中标南方电网网络架构优化调整项目 智能联动抑制未知威胁
  11. Mellanox:撑起国内超融合的网络天空
  12. 智能数码行业进销存软件排行榜前十名,看这篇就够了
  13. wherehows VM使用
  14. 扫雷(简易版) 10*10
  15. 计算机电源管理设置,如何修改计算机中设置的显卡电源管理模式
  16. UML - 类图的关系总结
  17. 【Unity3D开发小游戏】《太空射击游戏》Unity开发教程
  18. 冰点还原标准版-中文版(全面支持Windows 7)7.0.020.3172(最新版)下载与注册
  19. win7dns网络服务器未响应,Win7系统DNS服务器未响应问题的解决方法
  20. 美团 P2P 图书馆实践:5天时间1845册图书共享入库

热门文章

  1. linux设备驱动程序之时钟管理
  2. 【工具使用】Modsim32软件使用详解
  3. 安卓网页离线保存_Android webView 缓存 Cache + HTML5离线功能 解决
  4. Mac下Chrome添加.crx浏览器插件
  5. 备考进行时!2020年中级通信工程师传输与接入(无线)考试大纲
  6. 近世代数--环--环的一些基本概念
  7. 谷歌Chrome浏览器如何截图长图
  8. 2022版保姆级Idea调试jdk源码
  9. Ubuntu安装redis客户端工具及简单使用
  10. Android常用组件,太全了