北京理工大学 数据结构 实验报告 实验二简易计算器.docx
《北京理工大学 数据结构 实验报告 实验二简易计算器.docx》由会员分享,可在线阅读,更多相关《北京理工大学 数据结构 实验报告 实验二简易计算器.docx(10页珍藏版)》请在冰豆网上搜索。
![北京理工大学 数据结构 实验报告 实验二简易计算器.docx](https://file1.bdocx.com/fileroot1/2023-1/2/58d0cca7-6b8c-4d44-917e-eec810b79b70/58d0cca7-6b8c-4d44-917e-eec810b79b701.gif)
北京理工大学数据结构实验报告实验二简易计算器
实验二简易计算器
姓名:
任子龙学号:
1120140167班级:
05111451
一.需求分析
1.程序要求可对一实数算术表达式进行简单的数学运算, 可以识别带+、-、*、/、%、^(乘方)等等运算符及括号的中缀表达式,从键盘上输入一算术表达式(一般为中缀表达式),计算出表达式的值。
2.按照四则运算规则,求表达式的值。
一般规则如下:
1)先括号内,再括号外。
2)先乘方,再乘除,后加减。
b. 同级运算从左到右顺序执行。
3.有良好的提示信息,引导用户在键盘上输入规定的运算指令;如表达式有误,也应给出相应的提示信息。
4.建立两个工作栈,分别保存运算符,操作数或运算结果。
二.概要设计
1.抽象数据类型的定义
为实现上述功能,建立两个工作栈;算符为字符型变量,算数为单精度浮点型变量,则需要定义两种数据类型分别存储。
typedef struct StackChar{
char c;
struct StackChar *next;
}SC;
typedef struct StackFloat{
float f;
struct StackFloat *next;
}SF;
2.本程序包含两个模块
(1)主程序模块
主函数只包含了输入输出部分。
流程为:
首先输入算式,然后调用算符优先算法函数EvaluateExpression(s)进行计算,结果输出;然后循环下去,直到输入OUT指令,退出程序;
(2)链栈单元模块——实现栈的链式存储的抽象数据类型。
各函数之间的调用关系:
三.详细设计
1.结点类型
typedef struct StackChar{
char c;
struct StackChar *next;
}SC;
typedef struct StackFloat{
float f;
struct StackFloat *next;
}SF;
2.子函数
(1)算符优先算法的主干函数float EvaluateExpression(char* e)
实现算符优先算法主干的函数。
首先判断是算符还是算数,如果是算符,与算符栈栈顶元素进行优先级比较,如果该算符优先级比原栈顶元素优先级高,则进栈,否则进行运算;如果是算数,则入算数栈。
(2)进栈出栈函数
SC* Push(SC *s,char c);//使算符c进入算符栈
SF* Push(SF *s,float f);//使数值f进入数值栈
SC* Pop(SC *s);//使算符栈的栈顶元素出栈
SF* Pop(SF *s);//使数值栈的栈顶元素出栈
分别实现算符和数值的进栈和出栈操作,由EvaluateExpression函数直接调用。
(3)运算函数float Operate(float a,unsigned char t, float b);
进行运算,a,b为数,t为运算符 ,进行加减乘除或乘方运算,返回值为运算的结果。
(4)类型判断函数 Status In(char Test,char* TestOp); 判断是不是运算符 ,返回是或不是。
(5)优先级判断函数 char precede(char Aop, char Bop); 判断两个算符的优先级,返回'>'或'<'或'='。
(6)运算符识别函数int ReturnOpOrd(char op,char *TestOp); 判断是哪个运算符。
3.主函数
intmain()//主函数,用来输入输出和调用子函数
{
chars[128],a[4]="OUT";
提示信息;
k:
printf("\n请输入计算表达式:
");
scanf("%s",s);
if(strcmp(s,a))
{
printf("\n%s\b=%g\n",s,EvaluateExpression(s));//调用算符优先算法函数
gotok;
}
elseexit(0);
}
四.调试分析
1.为了提高程序的健壮性,在switch语句中加了case为“?
”的情况,对其它非法输入也进行考虑;
2.对关于栈的基本操作,在编写过程中暴露出问题;
2.如何实现按照运算法则进行计算真的特别难,好在老师在课堂上讲过算符优先算法,看到题目并不是很慌;同时也说明了编程时,好的算法意味着成功了一半。
五.测试结果
1.对给定的测试数据4.5+6.5*1.06=11.39,测试通过;
2.对于非法的输入,如2*(1+8*9(,给出错误提示;
3.输入大写OUT,直接退出程序。
六.附录
#include
#include
#include
#include
typedefintStatus;//将int定义为自定义数据类型
typedefstructStackChar{
charc;
structStackChar*next;
}SC;//存放算符的栈
typedefstructStackFloat{
floatf;
structStackFloat*next;
}SF;//存放数值的栈
charOPSET[9]={'+','-','*','/','(',')','#','^','%'};
unsignedcharPrior[9][9]={//算符间的优先级表,用于算符优先算法的判断
//'+''-''*''/''('')''#''^''%'
/*'+'*/'>','>','<','<','<','>','>','<','<',
/*'-'*/'>','>','<','<','<','>','>','<','<',
/*'*'*/'>','>','>','>','<','>','>','<','>',
/*'/'*/'>','>','>','>','<','>','>','<','>',
/*'('*/'<','<','<','<','<','=','?
','<','<',
/*')'*/'>','>','>','>','?
','>','>','>','>',
/*'#'*/'<','<','<','<','<','?
','=','<','<',
/*'^'*/'>','>','>','>','<','>','>','>','>',
/*'%'*/'>','>','>','>','<','>','>','<','>'};
//函数的声明
floatEvaluateExpression(char*e);//实现算符优先算法的函数
SC*Push1(SC*s,charc);//使算符c进入算符栈
SF*Push2(SF*s,floatf);//使数值f进入数值栈
SC*Pop1(SC*s);//使算符栈的栈顶元素出栈
SF*Pop2(SF*s);//使数值栈的栈顶元素出栈
floatOperate(floata,unsignedchart,floatb);//进行运算,a,b为数,t为运算符
StatusIn(charTest,char*TestOp);//判断是不是运算符,返回是或不是
charprecede(charAop,charBop);//判断优先级,返回'>'或'<'或'='
intReturnOpOrd(charop,char*TestOp);//判断是哪个运算符
floatEvaluateExpression(char*e)//算术表达式求值的算符优先算法。
{//设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合。
SC*OPTR=NULL;//算符栈,字符元素
SF*OPND=NULL;//数值栈,实数元素
charTempData[20];
floatData,a,b;
chartheta,*c,x,Dr[]={'#','\0'};
OPTR=Push1(OPTR,'#');
c=strcat(e,Dr);
strcpy(TempData,"\0");
while(*c!
='#'||OPTR->c!
='#')
{
if(!
In(*c,OPSET))//In(*c)判断是不是运算符;不是运算符则进栈
{
Dr[0]=*c;
strcat(TempData,Dr);//字符串连接函数
c++;
if(In(*c,OPSET))
{
Data=atof(TempData);//字符串转换函数
OPND=Push2(OPND,Data);
strcpy(TempData,"\0");
}
}
else
{
switch(precede(OPTR->c,*c))//precede(chara,charb)函数比较下一个字符和栈顶元素的优先级
{case'<':
//栈顶元素优先权低
OPTR=Push1(OPTR,*c);
c++;break;
case'=':
//脱括号并接收下一字符
OPTR=Pop1(OPTR);
c++;break;
case'>':
//退栈并将运算结果入栈
theta=OPTR->c;OPTR=Pop1(OPTR);
b=OPND->f;OPND=Pop2(OPND);
a=OPND->f;OPND=Pop2(OPND);
OPND=Push2(OPND,Operate(a,theta,b));break;
case'?
':
//输入非法,报错提示
printf("请输入正确的算术表达式!
\n");exit(0);
}
}
}
returnOPND->f;
}
SC*Push1(SC*s,charc)//使算符c进入算符栈
{
SC*p=(SC*)malloc(sizeof(SC));
p->c=c;
p->next=s;
returnp;
}
SF*Push2(SF*s,floatf)//使数值f进入数值栈
{SF*p=(SF*)malloc(sizeof(SF));
p->f=f;
p->next=s;
returnp;
}
SC*Pop1(SC*s)//使算符栈的栈顶元素出栈
{SC*q=s;
s=s->next;
free(q);
returns;
}
SF*Pop2(SF*s)//使数值栈的栈顶元素出栈
{
SF*q=s;
s=s->next;
free(q);
returns;
}
floatOperate(floata,unsignedchart,floatb)//进行运算,a,b为数,t为运算符
{
switch(t)
{
case'+':
returna+b;
case'-':
returna-b;
case'*':
returna*b;
case'/':
returna/b;
case'^':
returnpow(a,b);
case'%':
{intc,d;c=b/1;d=a/1;returnd%c;}
default:
return0;
}
}
StatusIn(charTest,char*TestOp)//判断是不是运算符,返回是或不是
{
inti=0;
intflag=0;
for(i=0;i<9;i++)
{
if(Test==TestOp[i])
flag=1;
}
returnflag;
}
charprecede(charAop,charBop)//判断优先级,返回'>'或'<'或'='
{
returnPrior[ReturnOpOrd(Aop,OPSET)][ReturnOpOrd(Bop,OPSET)];
}
intReturnOpOrd(charop,char*TestOp)//判断是哪个运算符
{inti=0;
for(i=0;i<9;i++)
if(op==TestOp[i])
returni;
}
intmain()//主函数,用来输入输出和调用子函数
{
chars[128],a[4]="OUT";
printf("*******************************************\n");
printf("简易计算器\n");
printf("*******************************************\n\n");
printf("使用说明:
\n");
printf("1.输入法为英文输入法;\n");
printf("2.由于不能区分负号和减号,不支持负数计算;\n");
printf("3.退出程序请输入大写OUT.\n");
printf("\n");
k:
printf("\n请输入计算表达式:
");
scanf("%s",s);
if(strcmp(s,a))
{
printf("\n%s\b=%g\n",s,EvaluateExpression(s));//调用算符优先算法函数
gotok;
}
else{printf("\n已退出计算器!
");exit(0);}
}