赞
踩
函数自己调用自己
如求阶乘函数:
int jiecheng(int n)
{
if(n==0)
return 1;
if(n==1)
return 1;
else
return n*jiecheng(n-1);
}
脑补一下如果在主函数里面调用这个函数输入5的话,函数返回5*jiecheng(4),所以这个函数还要继续调用下去,这就是自己调用自己的函数——递归函数。
举例说明:汉诺塔、阿克曼函数、阶乘、斐波那契数列
递归函数最后要返回 5!,但是他最开始只能知道答案是5乘一个函数的返回值,那么还要继续使用这个函数,但是5这个结果还不能扔了,所以就只能先将这个数据放起来,这时就用到了栈。
#include <iostream> using namespace std; void move(int n,char A,char B,char C); int step; int main() { int n; cout<<"input the number:"<<endl; cin>>n; move(n,'A','B','C'); return 0; } void move(int n,char A,char B,char C) { if(n==1) { step++; cout<<"["<<step<<"]move 1# from "<<A<<" to "<<C<<endl; } else { move(n-1,A,C,B); cout<<"["<<step<<"]move "<<n<<"# from "<<A<<" to "<<B<<endl; step++; move(n-1,B,A,C); } }
(楼上的陈年老代码也不知道是啥时候的,当时也是借鉴了别人的才整出来的)
Ackermann(a,b)函数定义如下:
若a=0,返回b+1。
若a>0且b=0,返回Ackermann(a-1,1)。
若a>0且b>0,返回Ackermann(a-1,Ackermann(a,b-1))。
递归形式
int digui(int a,int b)//递归函数
{
if(a==0)//分别对应三种情况
{
return b+1;
}
else if(b==0)
{
return digui(a-1,1);
}
else
{
return digui(a-1,digui(a,b-1));
}
}
递归的没啥好说,非递归稍提一下。
非递归
思路
只有第一种能告诉你答案是多少,所以都要最后归到第一类。
给你一对ab,按定义来,对应着不同的方式,第一第二不用说,第三种需要先记录当前的a,然后进入下一对ab的阿克曼函数计算。
在最后不需要新的函数时(也就是a为0了),这个时候能算出来一个值,到了最底层,这个时候就要返回了,
返回上一个函数或者是直接输出,在之前你是通过二三类才得到的答案,
但二类不改变当前的值,不管;
退回到第三类的时候,就是到了上一个函数,此时a、b的值都是定值了,再次计算就行了。
直到最后到达了初始,结束循环,返回结果。
很晕,那么就看一个例子(2,1)吧
代码分析
阿克曼函数有两个自变量,需要分别处理,所以创建两个栈分别处理。
因为原来的递归函数分为三种,所以在非递归里面思路相同,也要分三种情况分别讨论。
此时是递归到当前阿克曼函数最底层的过程,当a=0时结束,然后就是反过来计算的过程。
代码:
int xunhuan(int a,int b) { struct link* heada=(struct link*)malloc(sizeof(struct link)),* headb=(struct link*)malloc(sizeof(struct link));//两个栈,分别存入ab heada->next=NULL; headb->next=NULL; heada=input(heada,a);//开始先将ab压入栈 headb=input(headb,b); while(heada->next)//栈非空(两个栈应当是同时空,写一个即可) { while(a!=0)//a=0可直接求出来,跳出循环的条件 { if(b==0)//第二种情况 { a-=1; b=1; input(heada,a); input(headb,b);//再次压入栈 } else//最后一种麻烦的 { b-=1; input(heada,a-1); input(headb,-1);//特殊标识 } } b++;//a=0的情况 while(heada->next&&headb->next->data!=-1)//将没有用的输出 { output(heada); output(headb); } if(heada->next) { a=heada->next->data-1; output(headb); input(headb,b);//将b改为我们已经直到了的值,带入上层函数计算。 } }//外层while结束 return b; }
另附(2,1)栈的变化
另外说明一下,如果是递归的方式计算该函数,看看上面的图就知道很麻烦,虽然数值不大,但是(4,5)就可能让人崩溃,所以测试的时候建议选择小一点的例子。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。