逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在
数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
正常的表达式 逆波兰表达式
a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a=1,3 +
逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。
例如
(a+b)*(c+d) 转换为 ab+cd+*
下面是程序化算法流程:
1、建立
运算符栈stackOperator用于运算符的存储,压入'\0'。
2、预处理表达式,正、负号前加0(如果一个加号(减号)出现在最前面或左括号后面,则该加号(减号)为正负号) 。
3、顺序扫描表达式,如果当前字符是数字(优先级为0的符号),则直接输出该数字;如果当前字符为运算符或括号(优先级不为0的符号),则判断第4点 。
4、若当前运算符为'(',直接入栈;
若为四则运算符,比较栈顶元素与当前元素的优先级:
如果 栈顶元素运算符优先级 >= 当前元素的优先级,
出栈并顺序输出运算符直到 栈顶元素优先级 < 当前元素优先级,然后当前元素入栈;
如果 栈顶元素 < 当前元素,直接入栈。
5、重复第3点直到表达式扫描完毕。
6、顺序出栈并输出
运算符直到栈顶元素为'\0'。
#include <iostream>
#include <set>
#include <vector>
#include <map>
#include <list>
#include <math.h>
#include <stack>
using namespace std;
enum tErroCode{
kErrorCode_NoError ,
kErrorCode_DevideByZero,
kErrorCode_InvalitExpressionFound ,
};
int Precedence(char sign);
void makePostfixExpr(const char* exp,vector<string> &vec);
double str2double(const string &str);
double PostfixExprCalculation(vector<string> &vec, tErroCode &errorCode);
bool LegitimacyDetection(const char* pszCalcExpr);
double Calculate( const char* pszCalcExpr, tErroCode &errorCode );
void print(vector<string> &vec){
for(int i=0;i<vec.size();++i){
cout<<vec[i]<<" ";
}
cout<<endl;
}
/* Note:
* 1. we assume the following cases are legal
* a. 1 2 + 3 34 is equivalent to 12+334
* b. -1 + -2 / -3 is equivalent to (-1)+(-2)/(-3)
* 1 + -2 is equivalent to 1+(-2)
* while -1 + *2 / +3 is illegal, because *2 and +3 are illegal, we can change the code in function Str2Double() to make +3 legal
* c. . + 1 is equivalent to 0.0 + 1 also .1 and 1. equal 0.1 and 1.0 , they are both legal
*
*/
double Calculate( const char* pszCalcExpr, tErroCode & errorCode )
{
if(!LegitimacyDetection(pszCalcExpr)){
errorCode = kErrorCode_InvalitExpressionFound ;
return 0;
}
/*
*record postfix expression
*/
vector<string> vec;
/*
* change the expression to Postfix expression
* for instance ((1+(2+3)/4)/ -5 )/ -6 -> 1 2 3 + 4 / + (-5) / (-6) /
*/
makePostfixExpr(pszCalcExpr,vec);
// print(vec);
/*
*Calculate the postfix expression
*/
return PostfixExprCalculation(vec, errorCode);
}
int main()
{
freopen("in.txt","r",stdin);
char exp[1000];
tErroCode ec;
while(cin.getline(exp,1000)){
// cout<<exp<<endl;
printf("%.2lf %d\n",Calculate(exp,ec),ec);
ec=kErrorCode_NoError ;
}
return 0;
}
int Precedence(char sign)
{
switch(sign)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
case '%':
return 3;
case '(':
case ')':
return -1;
default:
return 0;
}
}
bool LegitimacyDetection(const char* pszCalcExpr){
/*Illegal case:
* 1. Mismatched of '(' and ')', like (1+2, 1+(3-(4/5)... are illegal
* 2. we put other detections in function PostfixExprCalculation() and str2double(), like 1/0, 1+2+*3, *1+/2 ... are illegal
* note: we assume space appear in the middle of an Operand is legal, like 1 2 + 3 equals to 12+3 and the result is 15, and .+1 equals 0.0+1=1.0
*/
// 1. Mismatched of '(' and ')'
stack<char> stk;
int i,len=strlen(pszCalcExpr),ret;
for(i=0;i<len;++i){
if(pszCalcExpr[i]=='('){
stk.push('(');
}else if(pszCalcExpr[i]==')'){
if(!stk.empty())
stk.pop();
else {
return false;
}
}
}
if(!stk.empty()) return false;
return true;
}
void makePostfixExpr(const char* exp,vector<string> &vec){
stack<char> stk;
stk.push('#');
int len=strlen(exp);
int p=0,ret;
string op=" ";
char pre_oper=' ';
/* 1. We split the expression into the form : Operand, Operator, Operand, ... Operator, Operand
* for example
* 1 + 2 + 3 -> 1, +, 2 , +, 3
* 1 + (2 + 3) -> 1, +, ( , 2, + , 3, )
* 1 -/ 2 +* 3 -> 1, -, /2, +, *3 Apparently /2 and *3 are illegal operand, we check them in the function Str2Double()
* 1 / -2 + 3 -> 1, /, -2, +, 3 -2 is a legal operand
*
* 2. After split the expression we change the expression to postfix expression
*
*/
while(p<len){
double x=0;
bool tag=false;
string num="";
while(exp[p]==' ')++p;// skip the space
if(pre_oper!=')'){
while(p<len&&(Precedence(exp[p])==1||Precedence(exp[p])==2)){
if(exp[p]!=' '){
num+=exp[p];
tag=true;
}
++p;
}
}
while(p<len&&Precedence(exp[p])==0){
if(exp[p]!=' '){
num+=exp[p];
tag=true;
}
++p;
}
if(tag){
vec.push_back(num);
}
if(p==len)break;
ret=Precedence(exp[p]);
// when the Operator is '(' push into the stack, if the operator is ')' pop the operators in the stack until reach '('
if(ret==-1){
if(exp[p]=='('){
stk.push(exp[p]);
}else{
while(stk.top()!='('){
op[0]=stk.top();
vec.push_back(op);
stk.pop();
}
stk.pop(); // pop the operator '('
}
}else {
// pop the operators in the stack until the operator on the top of stack has lower priority than the current operator
while(Precedence(stk.top())>=ret){
op[0]=stk.top();
vec.push_back(op);
stk.pop();
}
stk.push(exp[p]);
}
pre_oper=exp[p];
++p;
}
while(stk.top()!='#'){
op[0]=stk.top();
vec.push_back(op);
stk.pop();
}
}
double str2double(const string &str,tErroCode & errorCode){
//include dot operator, like 1.23
double sig=1,ret=0,n=10;
int len = str.length(),i,dot=str.find('.');
if(dot==-1)dot=len;
if(str[0]=='-'){
i=1;
sig=-1;
}
/*
* if an operand with prefix '+' is legal ,like +3
* then uncomment the following code
*/
// else if(str[0]=='+'){
// i=1;
// sig=1;
// }
else i=0;
for(;i<dot;++i){
if(!(str[i]>='0'&&str[i]<='9')){
errorCode = kErrorCode_InvalitExpressionFound ;
return 0;
}
ret=ret*10+str[i]-'0';
}
for(i=dot+1;i<len;++i){
ret=ret+(str[i]-'0')/n;
n*=10;
}
return ret*sig;
}
double PostfixExprCalculation(vector<string> &vec, tErroCode & errorCode){
stack<double> stk;
int i,len=vec.size();
string str;
for(i=0;i<len;++i){
str=vec[i];
// operator
if(Precedence(str[0])>0&&str.length()==1){
double x,y;
if(stk.size()<2){
errorCode=kErrorCode_InvalitExpressionFound ;
return 0;
}
y=stk.top();stk.pop();
x=stk.top();stk.pop();
switch(str[0]){
case '+':
x+=y;
break;
case '-':
x-=y;
break;
case '*':
x*=y;
break;
case '^':
x=pow(x,y);
break;
case '%':
if(y==0){
errorCode=kErrorCode_DevideByZero;
return 0;
}
x=(int)x%(int)y;
break;
case '/':
if(y==0){
errorCode=kErrorCode_DevideByZero;
return 0;
}
x/=y;
break;
}
stk.push(x);
}else{ //operand
double tmp= str2double(str,errorCode);
if(errorCode != kErrorCode_InvalitExpressionFound ){
stk.push(tmp);
}else {
return 0;
}
}
}
if(stk.empty()||stk.size()>1){
errorCode = kErrorCode_InvalitExpressionFound ;
return 0;
}
errorCode=kErrorCode_NoError;
return stk.top();
}