题目:已知Ackerman函数的定义如下:
(1)写出递归算法;
(2)写出非递归算法;
(3)根据递归算法,画出求akm(2,1)时栈的变化过程。
部分概念:
递归函数:一个直接调用自己或通过一系列的调用语句间接地调用自己的函数,称作递归函数。
递归工作栈:整个递归函数运行期间使用的数据存储区,每一层递归信息构成一个“工作记录”。当前执行层的工作记录必为递归工作栈栈顶,此记录称为“活动记录”,指示该记录的栈顶指针称为”当前环境指针“
递归直接按函数定义,if else语句分类执行。
递归算法如下:
int akm(int m, int n)
{
if (m==0) akm=n+1;
else if (n==0) akm=akm(m-1,1);
else{
g=akm(m,n-1);
akm=akm(m-1,g);
}
}//akm
转换为非递归算法时,需要递归工作栈的辅助,利用其“先进后出”的特性,逐层计算。
观察函数可知,仅m=0时函数不再嵌套,且n也非函数时才可解出确定值。可用栈顶指针指示层数,工作记录记录该层数下的m,n值,此处的m,n值仅为akm函数内的,上一层被影响的m值应逐层解套至其位置的时候再改变。以m,n非0为判断依据,由于m=0是停止嵌套的条件,故以m为主循环在外,嵌套以n为主的循环。由m=0出循环后还需检验层数,若非最外层(栈不为空,说明此时n还是函数)则还需继续,处理活动记录并下移当前环境指针,以此为判断依据再套一个循环。注意当栈空且m=0时还需一次计算。
非递归算法如下:
int akm1(int m, int n)
{
//S[MAX]为附设栈,top为栈顶指针
top=0;S[top].mval=m;S[top].nval=n;
do {
while (S[top].mval){
while(S[top].nval){
top++;S[top].mval=S[top-1].mval;
S[top].nval=S[top-1].nval-1;
}
S[top].mval--;S[top].nval=1;
}
if (top>0){
top--;
S[top].mval--;
S{top}.nval=S[top+1].nval+1;
}
} while (top!=0||S[top].mval!=0);
akm1=S[top].nval+1;
}//akm1
当计算akm(2,1)时,各参数变化如下
top | S.mavl | S.val | 执行操作 |
0 | 2 | 1 | top=0;S[top].mval=m;S[top].nval=n; |
1 | 2 | 0 | top++;S[top].mval=S[top-1].mval; S[top].nval=S[top-1].nval-1; |
1 | 1 | 1 | S[top].mval--;S[top].nval=1; |
2 | 1 | 0 | top++;S[top].mval=S[top-1].mval; S[top].nval=S[top-1].nval-1; |
2 | 0 | 1 | S[top].mval--;S[top].nval=1; |
1 | 0 | 2 | top--;S[top].mval--; S{top}.nval=S[top+1].nval+1; |
0 | 1 | 3 | top--;S[top].mval--; S{top}.nval=S[top+1].nval+1; |
1 | 1 | 2 | top++;S[top].mval=S[top-1].mval; S[top].nval=S[top-1].nval-1; |
2 | 1 | 1 | top++;S[top].mval=S[top-1].mval; S[top].nval=S[top-1].nval-1; |
3 | 1 | 0 | top++;S[top].mval=S[top-1].mval; S[top].nval=S[top-1].nval-1; |
3 | 0 | 1 | S[top].mval--;S[top].nval=1; |
2 | 0 | 2 | top--;S[top].mval--; S{top}.nval=S[top+1].nval+1; |
1 | 0 | 3 | top--;S[top].mval--; S{top}.nval=S[top+1].nval+1; |
0 | 0 | 4 | top--;S[top].mval--; S{top}.nval=S[top+1].nval+1; |
akm1=5 | akm1=S[top].nval+1; |
习题代码均来源于清华大学出版社《数据结构题集:C语言版》,仅作为自己的思路记录