实验目的:
1.掌握栈的定义及实现;
2.掌握利用栈求解算术表达式的方法。
实验要求:
1、 使用链式存储结构完成栈的各种基本操作;
2、 补充完成In(c), Preced(t1,t2),Operate(a,theta,b)三个函数。
实验题目:栈的基本操作及其应用
实验过程:
1、通过修改完善教材中的算法3.22,利用栈来实现算术表达式求值的算法。对算法3.22中调用的几个函数要给出其实现过程:
(1) 函数In(c):判断c是否为运算符;
(2) 函数Precede(t1,t2):判断运算符t1和t2的优先级;
(3) 函数Operate(a,theta,b):对a和b进行二元运算theta。
2、程序运行时,输入合法的算术表达式(中间值及最终结果要在0~9之间,可以包括加减乘除和括号),便可输出相应的计算结果。
实验提示:(仅供参考,每个函数的具体实现可以有多种方法,希望有创新)
1. 将栈的定义和实现单独保存在头文件“stack.h”中,然后在表达式求值的源程序中包含此头文件(即#include“stack.h”)。
2.表达式求值源程序的具体实现
(1) 主函数如下:
void main()
{
Printf(“请输入算术表达式,并以#结束.\n”);
Printf(“the result of expression is:%d\n”,EvaluateExpression());
}
(2) 函数EvaluateExpression的实现见算法3.22
(3) 函数In(c)的实现可以采用以下方式:
Status In(SElemType c)// 应在前面有定义typedef char SElemType;
{ // 判断c是否为运算符
switch(c)
{
case'+':return TRUE;
……//补充完整
default:return FALSE;
}
}
(4) 函数Precede(t1,t2)的实现可以采用以下形式:
SElemType Precede(SElemType t1,SElemType t2)
{ //根据教材表3.1,判断两个运算符的优先关系
SElemType f;
switch(t2)
{
case '+':
case '-':if(t1=='('||t1=='#')
f='<';
else
f='>';
break;
……//补充完整
}
return f;
}
(5) 函数Operate(a,theta,b)的实现可以采用以下方式:
SElemType Operate(SElemType a,SElemType theta,SElemType b)
{
SElemType c;
a=a-48;
b=b-48;
switch(theta)
{
case'+':c=a+b+48;
break;
……//补充完整
}
return c;
}
选做内容:进一步改进,使表达式的中间值及最终结果不局限于0~9之间的个位数。(如果完成要在实验报告中注明)。
实验结果:
输入:2*(4-1)+8
输出:14
该程序能够完成个位数的四则运算。
实验分析:
1.栈的操作的特点;
2.列举调试运行过程中出现的错误并分析原因。
要求:
(1) 程序要添加适当的注释,程序的书写要采用缩进格式。
(2) 程序要具在一定的健壮性,即当输入数据非法时,程序也能适当地做出反应。
(3) 程序要做到界面友好,在程序运行时用户可以根据相应的提示信息进行操作。
(4) 上传源程序到课堂派,源程序保存为calculator.cpp。
#include
#include
#include
#include
using namespace std;
#define MAXSIZE 100 //顺序栈存储空间的初始分配量
#define OK 1
#define ERROR 0
typedef int Status;
typedef char ElemType;
//链栈的存储结构
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode,*LinkStack;
//链栈初始化
Status InitStack(LinkStack &S)
{
S=NULL;
return OK;
}
//入栈操作
Status Push(LinkStack &S,char e)
{
LinkStack p;
p=new StackNode;
p->data=e;
p->next=S;
S=p;
return OK;
}
//链栈的出栈
Status Pop(LinkStack &S,char &e)
{
LinkStack p;
if(S==NULL) return ERROR;
e=S->data;
p=S;
S=S->next;
delete p;
return OK;
}
//取栈顶元素
char GetTop(LinkStack S)
{
if(S!=NULL)
return S->data;
}
//判断是否是运算符
bool In(char c)
{
if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')'||c=='#') return 1;
else return 0;
}
//比较OPTR栈顶元素和ch的优先级(运算符的优先级)
char Precede(char t1,char t2)
{
char f;
if(t1=='+'||t1=='-')
{
if(t2=='*'||t2=='/'||t2=='(') f='<';
else f='>';
}
else if(t1=='*'||t1=='/')
{
if(t2=='(') f='<';
else f='>';
}
else if(t1=='(')
{
if(t2==')') f='=';
else f='<';
}
else if(t1==')')
{
f='>';
}
else if(t1=='#')
{
if(t2=='=') f='=';
else f='<';
}
return f;
}
//计算简单算术式
char Operate(char a,char theta,char b)
{
char ans;
if(theta=='+') ans=(a-'0')+(b-'0')+'0';
else if(theta=='-') ans=(a-'0')-(b-'0')+'0';
else if(theta=='*') ans=(a-'0')*(b-'0')+'0';
else if(theta=='/') ans=(a-'0')/(b-'0')+'0';
return ans;
}
//构建函数,求解算数表达式
char EvaluateExpression()
{
printf("请输入一个表达式:\n");
StackNode *OPND;//定义运算数栈
StackNode *OPTR;//定义运算符栈
InitStack(OPND); //初始化OPND栈,压入操作数和运算结果
InitStack(OPTR); //初始化OPTR栈,压入操作符
char c;//起始输入#
cin>>c;
Push(OPTR,c); //将表达式起始符'#'压入OPTR栈顶
char ch;
cin>>ch;
while(ch!='#'||GetTop(OPTR)!='#') //用ch!='#'来判断表达式是否扫描完毕,表达式
{ //没有扫描完毕或OPTR栈顶元素不为'#'则继续执行
if(!In(ch))
{
Push(OPND,ch);
cin>>ch;
}
else
switch(Precede(GetTop(OPTR),ch))
{
case '<':
Push(OPTR,ch);cin>>ch;
break;
case '>':
char theta;
char a,b;
Pop(OPTR,theta);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,Operate(a,theta,b));
break;
case '=':
char x;
Pop(OPTR,x);
cin>>ch;
break;
}
}
return GetTop(OPND);
}
int main()
{
char res=EvaluateExpression();
printf("结果为:");
cout<
终于完成这个程序了啊,心里很高兴。过程一如既往的困难,因为自己的不细心和小失误,但还好坚持写完了。
书上代码还是不能全信啊,要独立思考。
有两个印象深刻的收获:
1、如何查bug?
第一遍我在查bug的时候照着书本一个字母一个字母的查,这办法挺傻的。
后来我就改变策略了。
如果程序出错了,(1)你可以把分函数一个一个执行,从而精确寻找错误,(2)在程序语句中插入如printf等,通过运行结果查找错误,(3)和别人正确的代码对比,把别人的分函数复制过来使用,精确寻找错误。
2、之前只注意到写程序的时候不能使用中文符号,没想到这次在输入中使用了中文符号致错,花了好长时间才找出来。