递归的缺点:
–递归算法解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等
–执行时间长、占用空间多
–主要原因:递归调用时的现场保护与恢复(相对于迭代过程而言)
一个反复执行过程,可否用循环结构实现?
递归调用时,返回点怎么记录?
递归返回时,如何接着以前的断点继续执行?
返回值如何处理:若当前是较深一层的递归调用,如何将返回值返回到上一层递归过程的引用位置上?
系统栈:保护现场、保存返回值、返回地址
消除递归的13条规则:
初始化
⑴ 在过程的开始部分,插入说明为栈的代码并将其初始化为空:
StackType Stack[1..SIZE]
Top ← 0
这个栈用来存放参数、局部变量和函数的值、每次递归调用的返回地址。——模拟“系统栈”的功能
⑵ 将标号L1附于第一条可执行语句。
...//说明部分//
L1:第一条可执行语句(递归调用的起始地址)
⑶ 将所有参数和局部变量的值存
入栈。
Top ← Top +1
Stack[Top] ← …(保护现场)
栈顶指针可作为一个全程变量来看待。
⑷ 建立第i个新标号Li,并将标号的下标i存入栈。这个标号的i值将用来计算返回地址。
Top ← Top +1
Stack[Top] ← i
此标号放在规则⑺所描述的程序段中。
⑸ 计算这次调用的各实在参数(可能是表达式)的值,并把这些值赋给相应的形式参数。
⑹ 插入一条无条件转向语句转向过程的开始部分:
goto L1
(以上完成一次递归调用)
⑺ 如果这过程是函数,则对递归过程中含有此次函数调用的那条语句做如下处理:将该语句的此次函数调用部分用从栈顶取回该函数值的代码来代替,其余部分的代码按原描述方式照抄,并将⑷中建立的标号附于这条语句上。
⑻ 如果栈为空,则执行正常返回。
if top = 0 then return(…)
⑼ 否则,将所有输出参数(带有返回值的出口参数,out/ inout型)的当前值赋给栈顶上的那些对应的变量。
Stack[n] ← … //这里只是赋值,不是退栈//
⑽ 如果栈中有返回地址标号的下标,就插入一条此下标从栈中退出的代码,并把这个下标赋给一个未使用的变量。
addr ← Stack[Top]
Top ← Top -1
⑾ 从栈中退出所有局部变量和参数的值并把它们赋给对应的变量。
⑿ 如果这个过程是函数,则插入
以下指令,这些指令用来计算
紧接在return后面的表达式并
将结果值存入栈顶。
Top ← Top +1
Stack[Top] ←表达式的值
⒀ 用返回地址标号的下标实现对
该标号的转向。
if addr = i then goto Li
运用上面13条规则,用非递归求解斐波那契数列
#include <iostream>
using namespace std;
/*
非递归求解斐波那契数列
*/
int func(int n)
{
int stack[100] = {0};
int top = 0;
//fn1存储f(n-1)的数值
//fn2存储f(n-2)的数值
int fn1=1,fn2=1,fn=0,addr,num=n;
L1:if(n>=2)
{
top = top + 1;
stack[top] = n;
top = top + 1;
stack[top] = 2;
n = n-1;
if(n>=2)
{
top = top + 1;
stack[top] = n;
top = top + 1;
stack[top] = 3;
n = n-1;
}
goto L1;
//求解fn
L2:
fn1 = fn2;
fn2 = stack[top];
top = top-1;
fn = fn1+fn2;
goto L4;
L3:
fn1 = fn2;
fn2 = stack[top];
top = top-1;
fn = fn2+fn1;
goto L4;
}
else
fn = n;
L4:if(top == 0)
return fn;
else
{
addr = stack[top];
top = top-1;
n = stack[top];
top = top-1;
top = top+1;
stack[top] = fn;
if(num%2 == 0)
{
if(addr == 2)
goto L2;
if(addr == 3)
goto L3;
}
else
{
if(addr == 3)
goto L2;
if(addr == 2)
goto L3;
}
}
}
int main()
{
int n;
while(cin>>n)
cout<<func(n)<<endl;
return 0;
}