一、实验目的和要求
目的:将阶乘的递归算法一步一步转换为非递归算法
要求:其它要求同作业-01要求。
二、实验环境
软件环境:visual stdio 2017
硬件环境:①CPU:Intel(R)Core(TM)i7-8565U CPU @1.80Ghz
②内存:8.0GB
三、实验内容
(1)用递归代码实现n!求解。
(2)利用转换规则(不简化) 将代码(1)转换为非递归代码。
(3)简化并梳理代码(2)的流程。
(4)用以上三个独立模块,测试6!的计算结果。
四、实验过程
4.1 任务定义和问题分析
运用转换规则将阶乘递归算法转换为非递归算法,再经过简化规则得到最终版本。
4.2 数据结构的选择和概要设计
涉及到的数据结构:自行设计的链栈,传入参数为2个,一个记录数据,一个记录“地址”
概要设计:第一个函数:阶乘递归算法
第二个函数:仅使用转换规则得到的非递归算法
第三个函数:经化简规则得到的非递归算法
4.3 详细设计
函数1:简单的尾递归算法

函数2:由五个规则进行转换
(1) 设置一个栈(不妨用S表示),并且开始时将其置为空。
(2) 在子程序入口处设置一个标号(不妨设为L0)。
(3) 对子程序中的每一递归调用,用以下几个等价操作来替换:
(a)保留现场:开辟栈顶存储空间,用于保存返回地址(不妨Li,i=1,2,3,…)、调用层中的形参和局部变量的值(最外层调用不必考虑)。
(b)准备数据:为被调子程序准备数据,即计算实在参数的值, 并赋给对应的形参
(c)转入(子程序)执行, 即执行goto L0。
(d)在返回处设一个标号Li(i=1,2,3,…),并根据需要设置以下语句:若函数需要返回值,从回传变量中取出所保存的值并传送到相应的位置。
(4) 对返回语句,可用以下几个等价操作来替换:
如果栈不空,则依次执行如下操作,否则结束本子程序,返回。
(a)回传数据:若函数需要返回值,将其值保存到回传变量中。
(b)恢复现场:从栈顶取出返回地址(不妨保存到X中)及各变量、形参值,并退栈。
(c)返回:按返回地址返回(即执行goto X)。
(5) 对其中的非递归调用和返回操作可照搬。

函数三:用简化规则进行简化
简化规则1:如果递归程序中只有一处递归调用,则在转换时,返回地址不必入栈。
由此可简化程序,得到流程图及相应的程序。
简化规则2:在模拟尾递归调用时,不必执行入栈操作。
经化简规则,可以得到流程图如下:

因此,可以写出代码如下:

五、测试及结果分析
5.1 实验数据
用三个函数测试6!的结果
5.2 结果及分析
六、实验收获
经过本次实验,我学会了如何将递归代码转换为非递归代码,这也说明了,有些非递归代码可以用递归实现,这样可以使代码简洁许多。
七、参考文献
教学ppt
八、附录(源代码)
#include<iostream>
using namespace std;
template<typename T>
struct Node
{
T data;
Node*next;
};
template<typename T>
class stack
{
public:
stack()
{
top1 = new Node<T>;
top1->next = NULL;
top2 = new Node<int>;
top2->next = NULL;
}
bool empty() { return top1 == NULL; }
void push(T data, int address)
{
Node<T>*s1 = new Node<T>;
s1->data = data;
s1->next = top1;
top1 = s1;
Node<int>*s2 = new Node<int>;
s2->data = address;
s2->next = top2;
top2 = s2;
}
void pop(T& data, int& address)
{
data = top1->data;
address = top2->data;
Node<T>*s1 = new Node<T>;
s1 = top1;
top1 = s1->next;
delete s1;
Node<T>*s2 = new Node<int>;
s2 = top2;
top2 = s2->next;
delete s2;
}
private:
Node<T>*top1;
Node<int>* top2;
};
int fact(int n)
{
if (n == 0) return 1;
return n * fact(n - 1);
}
int version1(int n)
{
stack<int> s; //规则1
int base = 1; //规则5
L0: //规则2
if (n > 0) //规则5
{
base *= n; //规则5
s.push(n-1, 1); //规则3.a
n = n - 1; //规则3.b
goto L0; //规则3.c
L1:; //规则3.d
}
if (!s.empty()) //规则4
{
int X; //规则4.a
s.pop(n, X); //规则4.b
if (X == 1) goto L1;//规则4.c
}
return base; //规则5
}
int version2(int n)
{
int base = 1;
while (n > 0)
{
base *= n--;
}
return base;
}
int main()
{
cout << fact(6) << endl;
cout << version1(6) << endl;
cout << version2(6) << endl;
}
本文通过实验介绍了如何将阶乘的递归算法转换为非递归算法,首先实现了一个简单的递归版本,然后利用转换规则将其转化为非递归代码,并进一步简化流程。实验在Visual Studio 2017环境下进行,测试了三个不同阶段的算法在计算6!时的正确性,加深了对递归与非递归算法的理解。

447

被折叠的 条评论
为什么被折叠?



