递归转非递归学习二:求斐波那契数列F(N)的值

上《数据结构》的网络课程学习了递归转非递归的机械式转换的方法之后,

先练习写了N的阶乘方法转非递归(模拟栈)的代码,然后试着将斐波那契数列求F(N)的值的过程(模拟栈)转化为非递归:

#include <iostream>
#include <stack>
using namespace std;

// (1). 设置工作栈中元素的结构体
struct Datatype
{
    int n;          // 当前输入数据n
    int fn;         // FibonacciSequence(n)的返回值
    int fn_1;       // 局部变量FibonacciSequence(n-1)的值
    int fn_2;       // 局部变量FibonacciSequence(n-2)的值
    int retAddr;    // 模仿返回地址,调用第i个递归函数的标示符为i(i=1,2,3,...,t);t+1为栈底标示符,也是结束符
};

int FibonacciSequence(int N)
{
    // (3). 增加非递归入口
    // 初始化
    Datatype currArea, areaTemp;    // 当前栈中的元素,和一个临时元素
    currArea.n = N;                 // 当前元素的n值
    currArea.fn = 0;
    currArea.fn_1 = 0;
    currArea.fn_2 = 0;
    currArea.retAddr = 3;           // 栈底"监视哨",作为整个循环的结束标志
    int retResult = 0;              // 存储最终结果的变量

    // (1). 设置一个工作栈
    stack<Datatype> s;
    s.push(currArea);

// (2). 设置t+2个语句标号(t为递归函数内调用本身的次数,编号分别为0,1,...,t+1)
// 由于例子中函数两次调用其本身,所以t=2
label0:                         // 递归总入口
    areaTemp = s.top();         // 获取栈顶元素的值,用来判断n的值
    if (currArea.n <= 1)        // 判断n的值小于等1,直接计算
    {
        s.pop();                // 弹出栈顶元素,赋予新值之后再入栈
        areaTemp.fn = currArea.n;   // n=0或者1时,FibonacciSequence(n) = n;
        s.push(areaTemp);
        goto label3;            // 转向递归调用总出口
    }

    // 依次将FibonacciSequence(n-1)...FibonacciSequence(1)入栈
    currArea.n--;
    currArea.fn = 0;
    currArea.fn_1 = 0;
    currArea.fn_2 = 0;
    currArea.retAddr = 1;   // 第一处递归FibonacciSequence(n-1)的入口
    s.push(currArea);
    goto label0;

// (4). 替换第i(i=1...t)个递归规则
label1:                     // 第一处递归函数的出口
    areaTemp = s.top();
    s.pop();
    currArea = s.top();
    s.pop();
    currArea.fn_1 = areaTemp.fn;    // 获得FibonacciSequence(n-1)的值,之后再入栈
    s.push(currArea);
    currArea.n = currArea.n - 2;
    currArea.retAddr = 2;           // 第二处递归FibonacciSequence(n-2)
    s.push(currArea);
    goto label0;                    // 进入递归总入口,为了计算第二处递归FibonacciSequence(n-2)的值
label2:                             // 第二个递归调用的出口
    areaTemp = s.top();
    s.pop();
    currArea = s.top();
    s.pop();
    currArea.fn_2 = areaTemp.fn;    // 获得FibonacciSequence(n-2)的值
    currArea.fn = currArea.fn_1 + currArea.fn_2; // 直接计算FibonacciSequence(n)的值
    s.push(currArea);
    goto label3;

label3:                             // 递归调用总出口,(6). 标号为t+1的语句格式
    areaTemp = s.top();
    switch(areaTemp.retAddr)
    {
    case 1:
        goto label1;
        break;
    case 2:
        goto label2;
        break;
    case 3:                         // 如果获得的是栈底元素,结束整个循环
        s.pop();                    // 退栈,清空栈
        retResult = areaTemp.fn;
        break;
    default:
        cerr << "error label number in stack!" << endl;
        break;
    }
    return retResult;
}

// 尾递归转非递归,用循环结构求斐波那契数列
int FibonacciSequence2(int n)
{
    if (n <= 1)
        return n;
    long fib1 = 0, fib2 = 1;
    for (int i = 2; i <= n; i++)
    {
        fib2 = fib1 + fib2;    // 得到新Fib2(n)的值
        fib1 = fib2 - fib1;    // 得到新Fib2(n-1)的值
    }
    return fib2;
}

int main()
{
    int number;
    cin >> number;
    cout << FibonacciSequence(number) << endl;
    cout << FibonacciSequence2(number) << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值