首先维护的是两个栈,我们这里暂且称为S1和S2,S1中的结果最后存的就是逆波兰表达式,S2中将用于暂时存放运算符并且在最终形成逆波兰表达式的时候,该栈是会清空的。下面我们看看怎样具体的形成逆波兰表达式。
在此首先定义一下运算符的优先级关系,从小到达排序,相同优先级没有用逗号隔开:(,+-,*,负号,)。
从左至右遍历一个给定的中序表达式,也就是我们常规的数学计算的表达式。
(1)如果遇到的是数字,我们直接加入到栈S1中;
(2)如果遇到的是左括号,则直接将该左括号加入到栈S2中;
(3)如果遇到的是右括号,那么将栈S2中的运算符一次出栈加入到栈S1中,直到遇到左括号,但是该左括号出栈S2并不加入到栈S1中;
(4)如果遇到的是运算符,包括单目运算符和双目运算符,我们按照下面的规则进行操作:
(1)如果此时栈S2为空,则直接将运算符加入到栈S2中;
(2)如果此时栈S2不为空,当前遍历的运算符的优先级大于等于栈顶运算符的优先级,那么直接入栈S2;
(3)如果此时栈S2不为空,当前遍历的运算符的优先级小于栈顶运算符的优先级,则将栈顶运算符一直出栈加入到栈S1中,直到栈为空或者遇到一个运算符的优先级小于等于当前遍历的运算符的优先级,此时将该运算符加入到栈S2中;
(5)直到遍历完整个中序表达式之后,栈S2中仍然存在运算符,那么将这些运算符依次出栈加入到栈S1中,直到栈为空。
按照上面的五条操作反复进行完成,那么栈S1中存放的就是逆波兰表达式。
注意:我在代码的实现上并没有将从s2中出栈的直接加入s1,而是直接计算了结果,最好s1中储存的就是表达式最后的结果。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <math.h> #include <stack> using namespace std; stack <int> s1; stack <char>s2; int compare(char x) { int y; switch(x) { case '+': y=2; break; case '-': y=2; break; case'*': y=3; break; case'/': y=3; break; case'(': y=4; break; case')': y=1; break; } return y; } void Count(char x) { int a,b,ans; b=s1.top(); s1.pop(); a=s1.top(); s1.pop(); if(x=='+') ans=a+b; else if(x=='-') ans=a-b; else if(x=='*') ans=a*b; else if(x=='/') ans=a/b; s1.push(ans); } main() { char str[110],s[110]; scanf("%s",str); int len=strlen(str); int i,j,h=0; for(i=0; i<len; i++) { if(str[i]>='0'&&str[i]<='9') { s[h++]=str[i]; } else { if(h!=0) { s[h]=0; s1.push(atoi(s));//将s中的字符串变为整数 } h=0; if(s2.empty()||str[i]=='(') s2.push(str[i]); else { while(!s2.empty()&&compare(str[i])<compare(s2.top())) { if(s2.top()=='('&&str[i]==')') { s2.pop(); break; } else if(s2.top()=='(') break; Count(s2.top()); s2.pop(); } if(str[i]!=')') s2.push(str[i]); } } } if(h!=0) { s[h]=0; s1.push(atoi(s)); } h=0; while(!s2.empty()) { char ss=s2.top(); s2.pop(); Count(ss); } printf("%d ",s1.top()); return 0; }