表达式求值课程设计报告.docx

上传人:b****7 文档编号:9272538 上传时间:2023-02-03 格式:DOCX 页数:19 大小:116.64KB
下载 相关 举报
表达式求值课程设计报告.docx_第1页
第1页 / 共19页
表达式求值课程设计报告.docx_第2页
第2页 / 共19页
表达式求值课程设计报告.docx_第3页
第3页 / 共19页
表达式求值课程设计报告.docx_第4页
第4页 / 共19页
表达式求值课程设计报告.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

表达式求值课程设计报告.docx

《表达式求值课程设计报告.docx》由会员分享,可在线阅读,更多相关《表达式求值课程设计报告.docx(19页珍藏版)》请在冰豆网上搜索。

表达式求值课程设计报告.docx

表达式求值课程设计报告

数据结构课程设计

设计说明书

 

算术表达式求值问题

学生姓名

白子健

学号

1318014057

班级

计本1302

成绩

指导教师

李军

 

计算机科学与技术系

2015年9月10日

数据结构课程设计评阅书

题目

算术表达式求值算法的实现

学生姓名

白子健

学号

1318014057

指导教师评语及成绩

成绩:

教师签名:

年月日

教研室意见

总成绩:

室主任签名:

年月日

课程设计任务书

2015—2016学年第一学期

专业:

计算机科学与技术学号:

1318014057姓名:

白子健

课程设计名称:

课程设计Ⅰ---数据结构课程设计

设计题目:

表达式求值算法的实现

完成期限:

自2015年9月1日至2015年9月12日共2周

设计内容及要求:

算术表达式求值是程序设计语言编译中的一个基本问题,通过栈实现表达式运算优先级的匹配和运算。

用C/C++语言编程实现任意算术表达式的求值,设计内容要求如下:

(1)表达式共有三种基本表示方法:

前缀法、中缀法、后缀法。

从表达式的这三种基本方法中任选一种方法进行编程求值。

(2)分析所选的表示方法,根据选定的表示方法确定对应的存储结构和相关算法。

(3)算法要能正确处理算术运算的优先级规则,即:

先括号内,后括号外的规则;运算先乘除,后加减;同级运算从左到右。

如下表达式:

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+(6*3+2)=50+(18+2)=50+20=70

算符优先算法就是根据这个运算优先关系来编译或者解释执行的。

 

2设计思路

2.1表达式的输入:

表达式从键盘输入,存入字符串数组中。

2.2运算的实现:

任何一个表达式都是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。

可以把运算符和界限符统称为算符,根据算术运算规则,在运算的每一步中,任意两个相继出现的算符opt1和opt2之间的优先关系至多是下面三种关系之一:

opt1

opt1=opt2,即opt1的优先级等于opt2;

opt1>opt2,即opt1的优先级高于opt2。

表1定义了算符间的优先关系:

Opt2

Opt1

+

-

*

/

#

+

>

>

<

<

<

>

>

-

>

>

<

<

<

>

>

*

>

>

>

>

<

>

>

/

>

>

>

>

<

>

>

<

<

<

<

<

=

NULL

>

>

>

>

NULL

>

>

#

<

<

<

<

<

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);c=getchar();}//不是运算符则进栈;

else{

switch(Precede(GetTop(OPTR),c)){

case‘<’:

//栈顶元素优先级低

Push(OPTR,c);

c=getchar();

break;

case‘=’:

//脱括号并接收下一字符

Pop(OPTR,x);

c=getchar();

break;

case‘>’:

//退栈并将运算结果入栈

Pop(OPTR,theta);

Pop(OPND,b);

Pop(OPND,a);

Push(OPND,Operate(a,theta,b));

break;

}//switch

}//while

ReturnGetTop(OPND);

}//EvaluateExpression

算法中还调用了两个函数。

其中Precede是判定运算符栈的栈顶运算符opt1与读入的运算符opt2之间优先关系的函数;Operate为进行二元运算aoptb的函数,如果是编译表达式,则产生这个运算的一组相应指令并返回存放结果的中间变量名;如果是解释执行表达式,则直接进行该运算,并返回运算的结果。

程序流程图如下:

 

4程序代码

#if0

/*

2015年9月8日09:

10:

14

表达式求值算法——算符优先算法的实现

*/

#endif

#defineDebuging0//当值为一时,开启调试

#include

#include

#include

#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;

typedefstruct{

/*定义运算符栈*/

OPERATOR*base;

OPERATOR*top;

intiStackSize;

}OPTRStack,*pOPTRStack;

charcOpt[]={'+','-','*','/','(',')','#','.'};

charcPriority[7][7]={

{'>','>','<','<','<','>','>'},

{'>','>','<','<','<','>','>'},

{'>','>','>','>','<','>','>'},

{'>','>','>','>','<','>','>'},

{'<','<','<','<','<','=',NULL},

{'>','>','>','>',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{

printf("输入中缀表达式有误!

\n");

continue;

}

}

return0;

}//main

intInitOPNDStack(pOPNDStackS){

//构造一个空栈,栈内数据类型为OPND(浮点数据)

S->base=(OPERAND*)malloc(STACK_INIT_SIZE*sizeof(OPERAND));

if(!

S->base)

exit(OVERFLOW);//这么写错误处理显然还不成熟

S->top=S->base;

S->iStackSize=STACK_INIT_SIZE;

returnOK;

}//InitOPNDStack

OPERANDGetOPNDTop(pOPNDStackS){

//读取栈顶元素,不删除栈顶元素

if(S->top==S->base)

exit(OVERFLOW);//栈空

return*(S->top-1);

}//GetOPNDTop

intPushOPND(pOPNDStackS,OPERANDe){

//将新的OPND元素入栈,栈满则增加空间

if(S->top-S->base>=S->iStackSize){

S->base=(OPERAND*)realloc(S->base,\

(S->iStackSize+STACKINCREMENT)*sizeof(OPERAND));

if(!

S->base)

exit(OVERFLOW);//空间不够了

S->top=S->base+S->iStackSize;

S->iStackSize+=STACKINCREMENT;

#ifDebuging

printf("增加OPND空间辣!

\n");

system("pause");

#endif

}//if

*(S->top++)=e;

returnOK;

}//PushOPND

intPopOPND(pOPNDStackS,OPERAND*e){

//若栈不空,删除S栈顶元素,并用e返回其值

if(S->top==S->base)

returnERROR;

*e=*(--S->top);

returnOK;

}//PopOPND

intInitOPTRStack(pOPTRStackS){

//构造一个空栈,栈内数据类型为OPTR

S->base=(OPERATOR*)malloc(STACK_INIT_SIZE*sizeof(OPERATOR));

if(!

S->base)

exit(OVERFLOW);//这么写错误处理显然还不成熟

S->top=S->base;

S->iStackSize=STACK_INIT_SIZE;

returnOK;

}//InitOPTRStack

OPERATORGetOPTRTop(pOPTRStackS){

//读取栈顶元素,不删除栈顶元素

if(S->top==S->base)

exit(OVERFLOW);//栈空

return*(S->top-1);

}//GetOPTRTop//哎。

重复造轮子

intPushOPTR(pOPTRStackS,OPERATORe){

//将新的OPTR元素入栈,栈满则增加空间

if(S->top-S->base>=S->iStackSize){

S->base=(OPERATOR*)realloc(S->base,\

(S->iStackSize+STACKINCREMENT)*sizeof(OPERATOR));

if(!

S->base)

exit(OVERFLOW);//空间不够

S->top=S->base+S->iStackSize;

S->iStackSize+=STACKINCREMENT;

#ifDebuging

printf("增加OPTR空间辣!

\n");

system("pause");

#endif

}//if

*(S->top++)=e;

returnOK;

}//PshOPTR

intPopOPTR(pOPTRStackS,OPERATOR*e){

//若栈不空,删除S栈顶元素,并用e返回其值

if(S->top==S->base)

returnERROR;

*e=*(--S->top);

returnOK;

}//PopOPTR

OPERANDOperate(OPERANDfOperandA,OPERATORcOperator,OPERANDfOperandB){

//将操作数计算后返回

switch(cOperator)

{

case'+':

return(fOperandA+fOperandB);

break;

case'-':

return(fOperandA-fOperandB);

break;

case'*':

return(fOperandA*fOperandB);

break;

case'/':

return(fOperandA/fOperandB);

break;

default:

printf("运算出了BUG。

中彩蛋了。

\n");

system("pause");

returnERROR;

}//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)!

='#'){

if(!

IsOpt(c)){

fTmp=0.0;

iTmp=c-'0';

c=Expression[i++];

while(!

IsOpt(c)){

iTmp=iTmp*10+c-'0';

c=Expression[i++];

}

if(c=='.'){

c=Expression[i++];

for(j=0.1;!

IsOpt(c);j*=0.1){

fTmp+=j*(c-'0');

c=Expression[i++];

}

}

//这里不需要了else

tmp=iTmp+fTmp;

PushOPND(&NumStack,tmp);

}

else

switch(cPriority[WhichOptNum(GetOPTRTop(&OptStack))][WhichOptNum(c)])

{

case'<':

PushOPTR(&OptStack,c);

c=Expression[i++];

break;

case'=':

PopOPTR(&OptStack,&c);//脱括号接收下一字符

c=Expression[i++];

break;

case'>':

PopOPTR(&OptStack,&opt);

PopOPND(&NumStack,&fOperandB);

PopOPND(&NumStack,&fOperandA);

PushOPND(&NumStack,Operate(fOperandA,opt,fOperandB));

break;

}//switch

}

tmp=GetOPNDTop(&NumStack);

free(NumStack.base);

free(OptStack.base);

returntmp;

}//EvaluateExpression

intWhichOptNum(charopt){

//检测操作符所在的位置

inti=0;

for(i=0;i

if(cOpt[i]==opt){

returni;

}

}

}//WhichOptNum

intIsOpt(charopt){

//判断是不是操作符

inti=0;

for(i=0;i

if(opt==cOpt[i])

returnTRUE;

}

returnERROR;

}//IsOpt

intCheckExpression(char*Expression){

//检查输入的合法性,合法返回1,否则返回0;

inti=0;

while(Expression[i]){

if((Expression[i]>='0'&&Expression[i]<='9')||IsOpt(Expression[i])){

if(IsOpt(Expression[i])&&IsOpt(Expression[i+1])\

&&(Expression[i]!

=')'&&Expression[i+1]!

='('))

return0;

else{

++i;

continue;

}

}

else{

return0;

}

}

if(!

Expression[i])

return1;

}//CheckExpression

 

5测试及分析

在数据范围不溢出的情况下本设计仅可能出现两种情况:

(1)输入正确的中缀表达式,输出正确的计算结果。

(2)输入错误的中缀表达式,报告输入错误并要求重新输入。

表5.1设计的试验结果:

输入

输出

(1)输入正确

50+(6*3+2)

70

5+5+5+5+5+5+5

35

4.5*3-(1+2)/1

10.5

(2)输入错误

6++8

“输入中缀表达式有误”

3++dh

“输入中缀表

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 科学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1