非递归-求解斐波那契数列

递归的缺点:
–递归算法解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等
–执行时间长、占用空间多
–主要原因:递归调用时的现场保护与恢复(相对于迭代过程而言)

一个反复执行过程,可否用循环结构实现?
递归调用时,返回点怎么记录?
递归返回时,如何接着以前的断点继续执行?
返回值如何处理:若当前是较深一层的递归调用,如何将返回值返回到上一层递归过程的引用位置上?

系统栈:保护现场、保存返回值、返回地址

消除递归的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;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值