版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/82939519
表达式求值是程序设计语言编译中的一个最基本问题。它的实现是栈应用的有一个典型例子。
这里使用算符优先法。
我们这里输入一个表达式,进行表达式的求值并且输出其后缀表达式。
运行结果:
算法思想:
拿当前扫描的运算符号与上一个比较优先级,当前扫描符号低或相等则进行上一个运算,需取最近的两个数。否则扫下个。
设操作符栈与操作数栈,运算符栈最初压如‘#’,逐个扫描符号。遇操作数则直接入栈,继续读下一字符。遇运算符则与栈顶运算符比较优先级,当前运算符优先级高,前面的运算还不应执行,则当前运算符入栈,读下一符号。否则栈顶运算符出栈,两操作数出栈,进行运算,所得结果入数栈,开始下次循环,不扫描新符号,重新比较刚才扫描到的运算符,与新栈顶运算符。如此重复直到栈顶运算符与当前符号均为#。
后缀表达式:对于扫描到的数字除了入数栈之外,同时入到另一个用于求后缀表达式的PEXP,当执行一次运算时,将执行的算符同时压入PEXP中,所有运算结束后,从栈底到栈顶输出序列即为表达式的后缀表达式。
现在还有一个问题:表达式中肯定有小数或者多位数,不一定是个位数,我们需要表示它们。首先定义一个c1字符表示上一个字符,如果上一个字符是.说明正在读取一个小数,然后用flag计算小数的位数,出现小数后就修改栈顶元素。反之,如果上一个元素是整数,说明读取的是一个多位数,就计算并修改栈顶元素。如果是个位数直接压入栈即可。
首先给出辅助函数:
判定运算符的栈顶运算符与读入的运算符之间优先关系。
char Precede(char c1,char c2){
//判定运算符的栈顶运算符与读入的运算符之间优先关系
char c;
switch(c1){
case '+':
case '-':
switch(c2){
case '+':
case '-':
case ')':
case '#':
c='>';
break;
default:
c='<';
}
break;
case '*':
case '/':
if(c2=='(')
c='<';
else
c='>';
break;
case '(':
if(c2==')')
c='=';
else
c='<';
break;
case ')':
c='>';
break;
case '#':
if(c2=='#')
c='=';
else
c='<';
}
return c;
}
进行二元运算 a theta b。
double Operate(double a,char theta,double b){
//进行二元运算 a theta b
double sum;
switch(theta)
{
case '+':
sum=a+b;
break;
case '-':
sum=a-b;
break;
case '*':
sum=a*b;
break;
case '/':
sum=a/b;
break;
}
return sum;
}
判断是不是运算符.
Status In(char c,char *OP){
//判断是不是运算符
for(int i=0;i<7;i++)
if(c==OP[i]) //是运算符
return TRUE;
return FALSE;
}
算法实现:
double EvaluateEvaluation(char * s){
//进行多项式的求值以及后缀表达式的输出
int i=0,len,flag=0;
double a,b,sum;
char c1=s[0],e;
char OP[7]={'+','-','*','/','(',')','#'}; //运算符数组
SqStack<char> OPTR; //运算符栈
SqStack<double> OPND; //运算数栈
SqStack<char> PEXP; //后缀表达式栈
InitStack(OPTR); //初始化栈
InitStack(OPND);
InitStack(PEXP);
len=strlen(s);
s[len]='#';
s[len+1]='\0';
Push(OPTR,'#');//压入一个‘#’
while(s[i]!='#'||GetTop(OPTR)!='#'){ //扫描每一个字符 如果同为‘#’退出循环
if(!In(s[i],OP)){ //如果不是运算符
Push(PEXP,s[i]);
if(In(s[i+1],OP)) //如果后一个字符是运算符压入一个空格
Push(PEXP,' ');
if(c1=='.') //如果上一个字符是小数点
flag++;
if(flag) {
SetTopElem(OPND,GetTop(OPND)+(double)(s[i]-'0')/pow(10,flag));//修改栈顶元素
flag++;
}
if(s[i]!='.'&&!flag){
if(!In(c1,OP)&&!StackEmpty(OPND))//如果上一个字符是数字,修改栈顶元素
SetTopElem(OPND,GetTop(OPND)*10+s[i]-'0');
else//否则压入运算数栈
Push(OPND,(double)(s[i]-'0'));
}
c1=s[i++]; //读取下一个字符
}
else{//如果是运算符
flag=0;
switch(Precede(GetTop(OPTR),s[i])){
case '>': //当前运算符优先级低
Pop(OPTR,e); //运算符出栈
Pop(OPND,b);
Pop(OPND,a);
Push(PEXP,e);
Push(OPND,Operate(a,e,b)); //将计算结果压入运算符栈
break;
case '=': //优先级相等
Pop(OPTR,e); //弹出运算符栈顶元素
c1=s[i++];
break;
case '<':
Push(OPTR,s[i]); //当前运算符优先级高 压入运算符栈
c1=s[i++];
break;
}
}//else
}//while
PrintStack(PEXP);//输出后缀表达式
sum=GetTop(OPND);
DestroyStack(OPTR);
DestroyStack(OPND);
DestroyStack(PEXP);
return sum; //返回运算数栈顶元素
}//intc