如何将递归转换为非递归
3个回答
展开全部
转化的方法一般有以下两种,一是递归转化为递推,用迭代的思想去求解,程序效率要高得多,如求Fabonacci数列问题;二是自己定义堆栈来模拟递归的过程,但会减低程序的可读性,如汉诺塔问题。
第一种方法比较简单,下面重点讲一下第二种方法。
设P是一个递归算法,假定P中共有m个值参和局部变量,共有t处递归调用P的语句,则把P改写成一个非递归算法的一般规则为:
1、 定义一个栈S,用来保存每次递归调用前值参和局部变量的当前值以及调用后的返回地址。即S应该含有m+1个域,且S的深度必须足够大,使得递归过程中不会发生栈溢出。
2、 定义t+2个语句标号,其中用一个标号标在原算法中的第一条语句上,用另一个标号标在作返回处理的第一条语句上,其余t个标号标在t处递归调用的返回地址,分别标在相应的语句上。
3、 把每一个递归调用语句改写成如下形式:
(1) 把值参和局部变量的当前值以及调用后的返回地址压入栈;
(2) 把值参所对应的实在参数表达式的值赋给值参变量;
(3) 无条件转向原算法的第一条语句;
4、 在算法结束前增加返回处理,当栈非空时做:
(1) 出栈;
(2) 把原栈顶中前m个域的值分别赋给各对应的值参和局部变量;
(3) 无条件转向由本次返回地址所指定的位置;
5、 增设一个同栈S的元素类型相同的变量,作为进出栈的缓冲变量,对于递归函数,还需要再增设一个保存函数值中间结果的临时变量,用这个变量替换函数体中的所有函数名,待函数结束之前,在把这个变量的值赋给函数名返回。
6、 在原算法的第一条语句之前,增加一条把栈置空的语句。
7、 对于递归函数而言,若某条赋值语句中包含两处或多处递归调用(假设为n处),则应首先把它拆成n条赋值语句,使得每条赋值语句只包含一处递归调用,同时对增加的n-1条赋值语句,要增设n-1个局部变量,然后按以上六条规则转换成非递归函数。
struct record{
node* a;
int state;
record(node* a,int state):a(a),state(state){}
};
void non_recursive_inorder(){
stack<record> s;
node* cur=root; //初始化状态
int state=0;
while(1){
if(!cur){ //如果遇到null结点,返回上一层
if(cur == root)break;//如果没有上一层,退出循环
cur=s.top().a;
state=s.top().state; //返回上层状态
s.pop();
}else if(state == 0){ //状态位0,执行第一个递归inorder(cur->left);
s.push(record(cur,1));//保存本层状态
cur=cur->left; //更新到下层状态
state=0;
}else if(state == 1){ //状态为1,执行print和inorder(cur->right)
printf("%d ",cur->x);
s.push(record(cur,2)); //保存本层状态
cur=cur->right; //进入下层状态
state=0;
}else if(state == 2){ //状态2,函数结束,返回上层状态
if(cur == root)break; //初始结点的退出状态,遍历结束
cur=s.top().a; //返回上层状态
state=s.top().state;
s.pop();
}
}
putchar(10);
}
第一种方法比较简单,下面重点讲一下第二种方法。
设P是一个递归算法,假定P中共有m个值参和局部变量,共有t处递归调用P的语句,则把P改写成一个非递归算法的一般规则为:
1、 定义一个栈S,用来保存每次递归调用前值参和局部变量的当前值以及调用后的返回地址。即S应该含有m+1个域,且S的深度必须足够大,使得递归过程中不会发生栈溢出。
2、 定义t+2个语句标号,其中用一个标号标在原算法中的第一条语句上,用另一个标号标在作返回处理的第一条语句上,其余t个标号标在t处递归调用的返回地址,分别标在相应的语句上。
3、 把每一个递归调用语句改写成如下形式:
(1) 把值参和局部变量的当前值以及调用后的返回地址压入栈;
(2) 把值参所对应的实在参数表达式的值赋给值参变量;
(3) 无条件转向原算法的第一条语句;
4、 在算法结束前增加返回处理,当栈非空时做:
(1) 出栈;
(2) 把原栈顶中前m个域的值分别赋给各对应的值参和局部变量;
(3) 无条件转向由本次返回地址所指定的位置;
5、 增设一个同栈S的元素类型相同的变量,作为进出栈的缓冲变量,对于递归函数,还需要再增设一个保存函数值中间结果的临时变量,用这个变量替换函数体中的所有函数名,待函数结束之前,在把这个变量的值赋给函数名返回。
6、 在原算法的第一条语句之前,增加一条把栈置空的语句。
7、 对于递归函数而言,若某条赋值语句中包含两处或多处递归调用(假设为n处),则应首先把它拆成n条赋值语句,使得每条赋值语句只包含一处递归调用,同时对增加的n-1条赋值语句,要增设n-1个局部变量,然后按以上六条规则转换成非递归函数。
struct record{
node* a;
int state;
record(node* a,int state):a(a),state(state){}
};
void non_recursive_inorder(){
stack<record> s;
node* cur=root; //初始化状态
int state=0;
while(1){
if(!cur){ //如果遇到null结点,返回上一层
if(cur == root)break;//如果没有上一层,退出循环
cur=s.top().a;
state=s.top().state; //返回上层状态
s.pop();
}else if(state == 0){ //状态位0,执行第一个递归inorder(cur->left);
s.push(record(cur,1));//保存本层状态
cur=cur->left; //更新到下层状态
state=0;
}else if(state == 1){ //状态为1,执行print和inorder(cur->right)
printf("%d ",cur->x);
s.push(record(cur,2)); //保存本层状态
cur=cur->right; //进入下层状态
state=0;
}else if(state == 2){ //状态2,函数结束,返回上层状态
if(cur == root)break; //初始结点的退出状态,遍历结束
cur=s.top().a; //返回上层状态
state=s.top().state;
s.pop();
}
}
putchar(10);
}
展开全部
用在自己调用自己的地方,用return跳出函数
本回答被提问者采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
很简单啊 :
int fib(int n){
if(n<=0) return 0;
if(n==1 || n==2) return 1;
else {
int a=1,b=1,c;
for(int i=3;i<=n;i++){
c=a+b;
a=b;
b=c;
}
}
return c
}
int fib(int n){
if(n<=0) return 0;
if(n==1 || n==2) return 1;
else {
int a=1,b=1,c;
for(int i=3;i<=n;i++){
c=a+b;
a=b;
b=c;
}
}
return c
}
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询
广告 您可能关注的内容 |