表达式求值课程设计报告文档格式.docx
- 文档编号:22408622
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:19
- 大小:116.64KB
表达式求值课程设计报告文档格式.docx
《表达式求值课程设计报告文档格式.docx》由会员分享,可在线阅读,更多相关《表达式求值课程设计报告文档格式.docx(19页珍藏版)》请在冰豆网上搜索。
运算先乘除,后加减;
同级运算从左到右。
如下表达式:
50+(6*3+2)
要求:
(1)用C/C++语言编写一个程序将这组学生成绩输入到计算机中,数据运算的存储逻辑结构为栈。
(2)程序要能正确处理表达式的优先级、输出正确运算结果。
最终设计成果形式为:
1、设计好的软件一套;
2、撰写一份课程设计说明书一份,打印并装订成册。
指导教师(签字):
教研室主任(签字):
批准日期:
1课题描述…………………………………………………………………………………………1
2设计思路…………………………………………………………………………………………2
3算法设计…………………………………………………………………………………………3
4程序代码…………………………………………………………………………………………5
5测试及分析……………………………………………………………………………………..12
6总结……………………………………………………………………………………………..13
参考文献…………………………………………………………………………………………..13
1课题描述
表达式求值是程序设计语言编译中的一个最基本问题。
表达式求值在计算机中的实现是栈结构在计算机中的一个典型应用。
这里使用“算符优先算法”实现表达式求值。
要把一个表达式翻译成正确求值的一个机器指令序列,或者直接对表达式求值,首先要能够正确解释表达式。
例如对表达式求值:
首先要了解算术四则运算的规则。
即:
先算括号内,后算括号外;
先乘除后加减;
同级运算顺序从左到右;
所以,这个表达式的运算顺序为:
50+(6*3+2)=50+(18+2)=50+20=70
算符优先算法就是根据这个运算优先关系来编译或者解释执行的。
2设计思路
2.1表达式的输入:
表达式从键盘输入,存入字符串数组中。
2.2运算的实现:
任何一个表达式都是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。
可以把运算符和界限符统称为算符,根据算术运算规则,在运算的每一步中,任意两个相继出现的算符opt1和opt2之间的优先关系至多是下面三种关系之一:
opt1<
opt2,即opt1的优先级低于opt2;
opt1=opt2,即opt1的优先级等于opt2;
opt1>
opt2,即opt1的优先级高于opt2。
表1定义了算符间的优先关系:
Opt2
Opt1
+
-
*
/
(
)
#
>
<
=
NULL
表1
输入的表达式(包含运算符和操作数)以字符串的形式输入,故需要一个字符串数组存储键盘的输入。
在对输入的表达式求值前,应先检查输入的合法性。
只有正确的输入才能输出正确的计算结果。
算符优先算法运算需要两个栈:
操作数栈(OPND)和运算符栈(OPTR)。
栈可以采用数组实现,并定义栈的相关操作:
初始化、压栈、出栈、判断栈满、判断栈空等相关操作。
输入的字符串解析分离出操作数和运算符,分别进入操作数栈和运算符栈。
运算始终在栈顶实现,最终操作数栈只剩一个元素,即运算结果。
3算法设计
使用两个工作栈:
一个称作OPTR,用以寄存运算符;
另一个称作OPTD,用以寄存操作数或运算结果。
算法的基本思想是:
(1)置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素;
(2)依次读入表达式中的每个字符,若是操作数则进入OPND栈,若是运算符则和OPTR栈的栈顶元素比较优先级后进行相应的操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前字符串读入的字符均为“#”)。
算法如下:
OperandTypeEvaluateExpression(){
//算术表达式求值的算符优先算法。
OPTR和OPND分别为运算符栈和运算数栈
//OP为运算符集合{+、-、*、/、(、)、#、.}
InitStack(OPTR);
Push(OPTR,‘#’);
InitStack(OPND);
c=getchar();
while(c!
=’#’||GetTop(OPTR)!
=’#’){
if(!
IsOpt(c)){Push(OPND,c);
}//不是运算符则进栈;
else{
switch(Precede(GetTop(OPTR),c)){
case‘<
’:
//栈顶元素优先级低
Push(OPTR,c);
break;
case‘=’:
//脱括号并接收下一字符
Pop(OPTR,x);
case‘>
//退栈并将运算结果入栈
Pop(OPTR,theta);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND,Operate(a,theta,b));
}//switch
}//while
ReturnGetTop(OPND);
}//EvaluateExpression
算法中还调用了两个函数。
其中Precede是判定运算符栈的栈顶运算符opt1与读入的运算符opt2之间优先关系的函数;
Operate为进行二元运算aoptb的函数,如果是编译表达式,则产生这个运算的一组相应指令并返回存放结果的中间变量名;
如果是解释执行表达式,则直接进行该运算,并返回运算的结果。
程序流程图如下:
4程序代码
#if0
/*
2015年9月8日09:
10:
14
表达式求值算法——算符优先算法的实现
*/
#endif
#defineDebuging0//当值为一时,开启调试
#include<
stdio.h>
stdlib.h>
string.h>
#defineOVERFLOW-2
#defineERROR0
#defineINFEASIBLE-1
#defineOK1
#defineTRUE1
#defineFALSE0
#defineOPERANDdouble
#defineOPERATORchar
#defineSTACK_INIT_SIZE100
#defineSTACKINCREMENT10
#defineMAX_QUEUE_SIZE100
#defineOPERATORNUM8//操作符的数量
typedefstruct{
/*定义操作数栈*/
OPERAND*base;
OPERAND*top;
intiStackSize;
}OPNDStack,*pOPNDStack;
/*定义运算符栈*/
OPERATOR*base;
OPERATOR*top;
}OPTRStack,*pOPTRStack;
charcOpt[]={'
+'
'
-'
*'
/'
('
)'
#'
.'
};
charcPriority[7][7]={
{'
'
},
='
NULL},
NULL,'
}
intInitOPNDStack(pOPNDStackS);
OPERANDGetOPNDTop(pOPNDStackS);
intPushOPND(pOPNDStack,OPERANDe);
intPopOPND(pOPNDStackS,OPERAND*e);
intInitOPTRStack(pOPTRStackS);
OPERATORGetOPTRTop(pOPTRStackS);
intPushOPTR(pOPTRStackS,OPERATORe);
intPopOPTR(pOPTRStackS,OPERATOR*e);
OPERANDOperate(OPERANDfOperandA,OPERATORcOperator,OPERANDfOperandB);
OPERANDEvaluateExpression(char*Expression);
intWhichOptNum(charopt);
intIsOpt(charopt);
intCheckExpression(char*Expression);
intmain(void){
//表达式求值——算符优先算法
OPERANDe=0.0;
charExpression[50]="
"
;
system("
colorf0"
);
while(OK)
{
fflush(stdin);
printf("
输入表达式:
"
gets(Expression);
strcat(Expression,"
#"
//printf("
%s"
cPriority);
if(CheckExpression(Expression)){
e=EvaluateExpression(Expression);
printf("
Answer=%f\n"
e);
}
else{
输入中缀表达式有误!
\n"
continue;
}
}
return0;
}//main
intInitOPNDStack(pOPNDStackS){
//构造一个空栈,栈内数据类型为OPND(浮点数据)
S->
base=(OPERAND*)malloc(STACK_INIT_SIZE*sizeof(OPERAND));
S->
base)
exit(OVERFLOW);
//这么写错误处理显然还不成熟
top=S->
base;
iStackSize=STACK_INIT_SIZE;
returnOK;
}//InitOPNDStack
OPERANDGetOPNDTop(pOPNDStackS){
//读取栈顶元素,不删除栈顶元素
if(S->
top==S->
//栈空
return*(S->
top-1);
}//GetOPNDTop
intPushOPND(pOPNDStackS,OPERANDe){
//将新的OPND元素入栈,栈满则增加空间
top-S->
base>
=S->
iStackSize){
S->
base=(OPERAND*)realloc(S->
base,\
(S->
iStackSize+STACKINCREMENT)*sizeof(OPERAND));
if(!
exit(OVERFLOW);
//空间不够了
base+S->
iStackSize;
iStackSize+=STACKINCREMENT;
#ifDebuging
增加OPND空间辣!
system("
pause"
}//if
*(S->
top++)=e;
}//PushOPND
intPopOPND(pOPNDStackS,OPERAND*e){
//若栈不空,删除S栈顶元素,并用e返回其值
returnERROR;
*e=*(--S->
top);
}//PopOPND
intInitOPTRStack(pOPTRStackS){
//构造一个空栈,栈内数据类型为OPTR
base=(OPERATOR*)malloc(STACK_INIT_SIZE*sizeof(OPERATOR));
}//InitOPTRStack
OPERATORGetOPTRTop(pOPTRStackS){
//栈空
}//GetOPTRTop//哎。
。
重复造轮子
intPushOPTR(pOPTRStackS,OPERATORe){
//将新的OPTR元素入栈,栈满则增加空间
base=(OPERATOR*)realloc(S->
iStackSize+STACKINCREMENT)*sizeof(OPERATOR));
//空间不够
增加OPTR空间辣!
}//PshOPTR
intPopOPTR(pOPTRStackS,OPERATOR*e){
}//PopOPTR
OPERANDOperate(OPERANDfOperandA,OPERATORcOperator,OPERANDfOperandB){
//将操作数计算后返回
switch(cOperator)
case'
:
return(fOperandA+fOperandB);
break;
return(fOperandA-fOperandB);
return(fOperandA*fOperandB);
return(fOperandA/fOperandB);
default:
运算出了BUG。
中彩蛋了。
}//Operate
OPERANDEvaluateExpression(char*Expression){
//算符优先算法
OPNDStackNumStack;
OPTRStackOptStack;
charc='
'
inti=0;
OPERATORopt=0;
OPERANDtmp=0.0,fTmp=0.0,iTmp,j=0.0,fOperandB,fOperandA;
InitOPNDStack(&
NumStack);
InitOPTRStack(&
OptStack);
PushOPTR(&
OptStack,'
c=Expression[i++];
while(c!
='
||GetOPTRTop(&
OptStack)!
){
IsOpt(c)){
fTmp=0.0;
iTmp=c-'
0'
c=Expression[i++];
while(!
iTmp=iTmp*10+c-'
c=Expression[i++];
}
if(c=='
for(j=0.1;
!
IsOpt(c);
j*=0.1){
fTmp+=j*(c-'
c=Expression[i++];
}
//这里不需要了else
tmp=iTmp+fTmp;
PushOPND(&
NumStack,tmp);
else
switch(cPriority[WhichOptNum(GetOPTRTop(&
OptStack))][WhichOptNum(c)])
{
case'
PushOPTR(&
OptStack,c);
break;
PopOPTR(&
OptStack,&
c);
//脱括号接收下一字符
opt);
PopOPND(&
NumStack,&
fOperandB);
fOperandA);
PushOPND(&
NumStack,Operate(fOperandA,opt,fOperandB));
}//switch
tmp=GetOPNDTop(&
free(NumStack.base);
free(OptStack.base);
returntmp;
intWhichOptNum(charopt){
//检测操作符所在的位置
for(i=0;
i<
OPERATORNUM;
++i){
if(cOpt[i]==opt){
returni;
}//WhichOptNum
intIsOpt(charopt){
//判断是不是操作符
if(opt==cOpt[i])
returnTRUE;
returnERROR;
}//IsOpt
intCheckExpression(char*Expression){
//检查输入的合法性,合法返回1,否则返回0;
while(Expression[i]){
if((Expression[i]>
&
&
Expression[i]<
9'
)||IsOpt(Expression[i])){
if(IsOpt(Expression[i])&
IsOpt(Expression[i+1])\
(Expression[i]!
Expression[i+1]!
))
return0;
else{
++i;
continue;
return0;
Expression[i])
return1;
}//CheckExpression
5测试及分析
在数据范围不溢出的情况下本设计仅可能出现两种情况:
(1)输入正确的中缀表达式,输出正确的计算结果。
(2)输入错误的中缀表达式,报告输入错误并要求重新输入。
表5.1设计的试验结果:
输入
输出
(1)输入正确
70
5+5+5+5+5+5+5
35
4.5*3-(1+2)/1
10.5
(2)输入错误
6++8
“输入中缀表达式有误”
3++dh
“输入中缀表
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 表达式 求值 课程设计 报告