您的位置:首页 > 其它

递归转非递归学习三:汉诺塔问题

2013-11-29 10:50 253 查看
在学习了递归转非递归的机械式转换的方法之后,先练习写了N的阶乘方法转非递归(模拟栈)的代码,然后练习将斐波那契数列求F(N)转非递归(模拟栈)

最后在写汉诺塔问题转非递归过程中花了更多一些时间,中途因为没有保存调用递归之前的一组局部变量,导致一直没有得到正确答案。

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

// (1). 设置一个工作栈
struct Datatype
{
    short int retAddr;      // 模仿返回地址
    int nParam;             // 当前SimTower中的参数n
    char fromParam;         // 当前SimTower中的参数fromPeg
    char auxParam;          // 当前SimTower中的参数auxPeg
    char toParam;           // 当前SimTower中的参数toPeg

    /* 注意:之前的犯了一个错,没有申请下面的变量
       这些变量保存,调用递归函数之前的一些数据,
       返回时第二个cout语句中会用到*/
    int nParam_before;      // 进入SimTower之前,n的值,
    char fromParam_before;  // 进入SimTower之前,fromPeg的值,
    char auxParam_before;   // 进入SimTower之前,auxPeg的值,
    char toParam_before;    // 进入SimTower之前,toPeg的值,
};

void SimTower(int n, char fromPeg, char auxPeg, char toPeg)
{
    Datatype currArea, tempArea;    // 当前工作区
    stack<Datatype> s;              // 模拟系统运行时的栈

    // (3). 非递归入口,当前工作区初始化
    currArea.retAddr = 3;           // 压在栈底作”监视哨",最后访问的结束,跳至lable3
    currArea.nParam = n;
    currArea.fromParam = fromPeg;   // 修改当前变量param
    currArea.auxParam = auxPeg;
    currArea.toParam = toPeg;

//    第一处进入SimTower,下面变量未知。由于循环中没有用到,可以不用初始化
//    currArea.nParam_before = -1;
//    currArea.fromParam_before = ' ';
//    currArea.auxParam_before = ' ';
//    currArea.toParam_before = ' ';

    s.push(currArea);               // 当前工作区入栈

label0:                             // 递归总入口
    tempArea = s.top();
    if (tempArea.nParam == 1)       // 递归结束条件
    {
        cout << "Move Disk 1 from Peg " << tempArea.fromParam << " to Peg " << tempArea.toParam << endl;
        goto label3;
    }
    // 递归总入口
    // 保存进入递归函数之前的数据
    currArea.retAddr = 1;
    currArea.nParam_before = tempArea.nParam;
    currArea.fromParam_before = tempArea.fromParam;
    currArea.auxParam_before = tempArea.auxParam;
    currArea.toParam_before = tempArea.toParam;

    // 获取递归参数列表中的数据
    currArea.nParam = currArea.nParam_before - 1;
    currArea.fromParam = currArea.fromParam_before;
    currArea.auxParam = currArea.toParam_before;
    currArea.toParam = currArea.auxParam_before;

    s.push(currArea);
    goto label0;

label1:     // 第一个递归语句调用结束,退栈;第二个递归调用的入口
    currArea = s.top();
    s.pop();
    cout << "Move Disk " << currArea.nParam_before << " from Peg " << currArea.fromParam_before << " to Peg " << currArea.toParam_before << endl;

    /* 进入第二个递归调用和第一个递归调用时,n,fromPeg,auxPeg,toPeg相同
       所以不用更改;只需要修改传入时的n,fromPeg,auxPeg,toPeg*/
    currArea.retAddr = 2;               // 第二处递归的地址标志
    currArea.fromParam = currArea.auxParam_before;
    currArea.auxParam = currArea.fromParam_before;
    currArea.toParam = currArea.toParam_before;

    s.push(currArea);
    goto label0;

label2:     // 第二个递归语句调用结束,退栈
    currArea = s.top();
    s.pop();
    goto label3;
label3:
    tempArea = s.top();
    switch(tempArea.retAddr)
    {
    case 1:
        goto label1;
    case 2:
        goto label2;
    case 3:
        s.pop();
        return;
    }
}

int main()
{
    SimTower(4, 'A', 'B', 'C');
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: