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;iif(cOpt[i]==opt){
returni;
}
}
}//WhichOptNum
intIsOpt(charopt){
//判断是不是操作符
inti=0;
for(i=0;iif(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
“输入中缀表