上《数据结构》的网络课程学习了递归转非递归的机械式转换的方法之后,
先练习写了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;
}