表达式求值与后缀表达式

时间:2020-12-23 11:30:50
 一个算术表达式,含有数字(为简化处理,数字只有一位),运算符:+、-、*,以及括号,求表达式的值。


 给出的表达式是一般我们见到的中缀表达式,即运算符位于操作数之间。如果把中缀表达式转化为后缀表达式,那么对后缀表达式求值将会很方便。


 后缀表达式特点:


  1.操作符位于操作数之后;


  2.没有括号;


  3.运算符没有优先级。


 中缀表达式转化为后缀表达式的步骤:


  1.初始化一个空操作符栈和空结果字符串;


  2.从前到后读取中缀表达式的字符,如果是操作数,加到结果字符串后面;


  3.如果是操作符,分两种情况入栈:


    a.如果待入栈操作符优先级大于栈顶操作符,直接入栈;


    b.如果待入栈操作符优先级小于或等于栈顶操作符,栈顶操作符加到结果字符串后面;重复b过程直到遇到前括号‘(’或栈顶操作符优先级比待入栈操作符小,待入栈操作符入栈。


  4.如果是前括号‘(’,直接入栈;


  5.如果是后括号,将栈中操作符依次弹出,直至遇到一个前括号‘(’结束。前括号出栈。


  最后结果字符串就是后缀表达式。


  后缀表达式求值的步骤:


  1.初始化一个空操作数栈;


  2.从前到后读取后缀表达式字符。如果是操作数直接入栈。如果读到一个操作符@,弹出栈顶元素a和新的栈顶元素b,执行b @ a,将结果压入栈中;


  3.最后栈中只剩下一个元素,即表达式的值。


 


  关于中缀表达式转换成后缀表达式与后缀表达式正确性的说明:


  先观察一些例子:


  1.假设中缀表达式没有括号,且所有运算符优先级相同。比如a+b-c+d-e+f ,将被转化为ab+c-d+e-f+。此时用括号来说明后缀表达式执行顺序:((((( ab+ ) c- ) d+ ) d- ) f+ ),运算顺序没有改变。


  2.假设中缀表达式没有括号,但是运算符优先级不同。比如a+b*c+d-e*f,将被转化为 abc*+d+ef*-,用括号来说明后缀表达式执行顺序:((( a ( bc* ) + ) d+ ) ( ef* ) - ),运算顺序依然没有变。


  3.假设中缀表达式有括号。比如(a+b)*(c+d)*e+f,将被转化为ab+cd+*e*f+,用括号表示执行顺序(((( ab+ ) ( cd+ ) * ) e* ) f+ )。运算顺序还是没有改变。


 


  不难观察出以下5点:


  1.后缀表达式中操作数出现的顺序和中缀表达式一样。这是因为操作数是直接加入结果字符串;


  2.每个操作符都会入栈一次,出栈一次;


  3.在没有括号时,如果相邻两个操作符优先级相同或前一个操作符的优先级高,则后缀表达式中操作符出现的顺序和中缀表达式一样。因为后一个操作符入栈时,栈顶元素一定是前一个相邻的操作符,如果其优先级小于等于待入栈的,则前一个操作符被弹出并加入结果字符串,后缀表达式中操作符顺序得到保持。


  4.在没有括号时,如果相邻两个操作符,后者优先级大与前者,后者将直接被压入栈中,且位于前者之上。在出栈时,后者将先出栈,因而后缀表达式中,操作符顺序发生交换,即中缀表达式中要先运算的操作在后缀表达式中出现在前面。


  5.出现括号。括号中的处理因为遵循前4点,不再赘述,而括号的内容作为一个整体的性质得到维护。


  参考文章:


  http://blog.csdn.net/daheiantian/article/details/6553713


  http://blog.csdn.net/niushuai666/article/details/6702964


  http://www.cnblogs.com/luna-lovegood/archive/2012/07/17/2596464.html




//数据结构与算法
//利用后缀表达式对算数表达式求值
//不含符号变量处理,且数字都是一位,运算符仅含+、-、*和括号
#include
#include
#include
#define NUM 200

using namespace std;

char s[NUM],a[NUM],stack[NUM];
int stacknum[NUM];

int trans(char s[NUM],char a[NUM],char stack[NUM],int lens){
int lena = 0,top = 0;
for(int i=0; i){
if(s[i]>='0' && s[i]<='9'){
a[lena++] = s[i];
}
else if(s[i]=='+' || s[i]=='-'){
while(top>0 && stack[top-1]!='(')
a[lena++] = stack[--top];
stack[top++] = s[i];
}
else if(s[i] == '*'){
while(top>0 && stack[top-1]!='(' && stack[top-1]!='+' && stack[top-1]!='-')
a[lena++] = stack[--top];
stack[top++] = s[i];
}
else if(s[i]=='(')
stack[top++] = s[i];
else if(s[i]==')'){
while(top>0 && stack[top-1]!='(')
a[lena++] = stack[--top];
top--;
}
}
while(top>0){
a[lena++] = stack[--top];
}
return lena;
}

int calcu(char a[NUM],int stack[NUM],int lena){
int top=0;
for(int i=0; i)
if(a[i]>='0' && a[i]<='9')
stack[top++] = a[i]-'0';
else{
if(a[i]=='+')
stack[top-2] = stack[top-2] + stack[top-1];
else if(a[i] == '-')
stack[top-2] = stack[top-2] - stack[top-1];
else if(a[i]=='*')
stack[top-2] = stack[top-2] * stack[top-1];
top--;
}
return stack[0];
}

int main()
{
int ans,lens,lena;
gets(s);
lens = strlen(s);
lena = trans(s,a,stack,lens);//将中缀表达式转换横后缀表达式,返回值是后缀表达式a的长度
ans = calcu(a,stacknum,lena);//计算后缀表达式值
printf("%d\n",ans);
return 0;
}