两种情况:
1. 根据输入的算数表达式,如(56-20) /(4+2), 先转化为后缀表达式(逆波兰式)56#20#-4#2#+/ 因为输入的数字有多位数的(56),所以数之间用#隔开,然后根据后缀表达式求值。
2.根据输入的算数表达式,直接进行求值。
对于情况1:
转化为后缀表达式时用到了一个符号栈,把后缀表达式存放到数组postExp中,根据后缀表达式求值时用到了一个运算数栈,运算完后,栈顶即为所求。
完整代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <stack> #include <queue> using namespace std; const int maxOp = 7;//符号的总数 struct Pri //设定运算符优先级 { char ch; //运算符 int pri; //优先级 }lpri[] = {{'=', 0}, {'(', 1}, {'*', 5}, {'/', 5}, {'+', 3}, {'-', 3}, {')', 6}}, rpri[] = {{'=', 0}, {'(', 6}, {'*', 4}, {'/', 4}, {'+', 2}, {'-', 2}, {')', 1}}; int LeftPri(char op)//求左运算符op的优先级 { for(int i = 0; i < maxOp; ++ i) if(lpri[i].ch == op) return lpri[i].pri; } int RightPri(char op)//求右运算符op的优先级 { for(int i = 0; i < maxOp; ++ i) if(rpri[i].ch == op) return rpri[i].pri; } bool IsOp(char ch)//判断符号ch是否为运算符 { if(ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*' || ch == '/') return true; return false; } int Precede(char op1, char op2) //op1和op2运算符优先级的比较结果 { int lPri = LeftPri(op1); int rPri = RightPri(op2); if(lPri == rPri) return 0; else if(lPri < rPri) return -1; else return 1; } void TransToPostExp(char* exp, char postExp[]) //将算数表达式exp转换成后缀表达式 { stack<char>opStack;//运算符栈 opStack.push('=');// =入栈,其优先级最低 int i = 0;//后缀表达式字符指针 while(*exp != '\0') { if(!IsOp(*exp)) //如果不是运算符 { while(*exp >= '0' && *exp <= '9')//是数字 { postExp[i ++] = *exp; exp ++; } postExp[i ++] = '#'; //用'#'表示一个数值串的结束,比如456# } else { int cmpPri = Precede(opStack.top(), *exp); if(cmpPri == 0) //左右运算符优先级相等,也就是()这种情况 { opStack.pop();// '('退栈 exp ++; } else if(cmpPri == -1) //栈顶运算符优先级低 { opStack.push(*exp);//入栈,符号栈栈顶始终是优先级最高的 exp ++; } else //栈顶运算符优先级高 { while(Precede(opStack.top(), *exp) == 1)//不断退栈 { postExp[i ++] = opStack.top(); opStack.pop(); } //opStack.push(*exp); // exp ++; 一定要注意!不能这样写,因为有可能当前字符是')' } } } while(opStack.top() != '=')//exp扫描完毕,退栈到' = '为止 { postExp[i ++] = opStack.top(); opStack.pop(); } postExp[i] = '\0';//postExp表达式添加结束标识 } void GetTwoFromStack(stack<double>& numStack, double& a, double& b)//从运算数栈中获取两个数,栈顶和次栈顶 { a = numStack.top(); numStack.pop(); b = numStack.top(); numStack.pop(); } float CalFromPostExp(char* postExp)//计算后缀表达式的值 { stack<double> numStack;//运算数栈 double a, b; while(*postExp != '\0') { switch(*postExp) { case '#': break; case '+': GetTwoFromStack(numStack, a, b);//获取运算数栈的两个数 numStack.push(b + a);//进行运算,再压入运算数中 break; case '-': GetTwoFromStack(numStack, a, b); numStack.push(b - a); break; case '*': GetTwoFromStack(numStack, a, b); numStack.push(b * a); break; case '/': GetTwoFromStack(numStack, a, b); if(a != 0) numStack.push(b / a); else { cout << "除0错误! " <<endl; exit(0); } break; default: //处理数字字符 int n = 0; while(*postExp >= '0' && *postExp <= '9') { n = n * 10 + (*postExp - '0'); postExp ++; } numStack.push(n); break; } postExp ++; //继续处理字符 } return numStack.top(); } char exp[50]; char postExp[50]; int main() { while(cin >> exp) { cout << "中缀表达式为: " << exp <<endl; TransToPostExp(exp, postExp);//将算数表达式转化为后缀表达式,比如输入(56-20)/(4+2) ,输出 56#20#-4#2#+/ cout << "后缀表达式为: " << postExp <<endl; cout << "表达式的值为: " <<CalFromPostExp(postExp) << endl << endl; } return 0; }
else //栈顶运算符优先级高 { while(Precede(opStack.top(), *exp) == 1)//不断退栈 { postExp[i ++] = opStack.top(); opStack.pop(); } //opStack.push(*exp); // exp ++; 一定要注意!不能这样写,因为有可能当前字符是')' }
不要把')'加入到符号栈中,opStack.push(*exp);
也不要直接忽略')'而继续扫描下一个字符,因为此时栈顶可能时'(',需要进行下一轮的比较,把'('出栈, 所以不能写 exp ++.
也就是说 这里需要特别考虑 当前字符是 ')'的情况
对于情况2:
用到了两个栈,符号栈和运算数栈,对输入的运算数表达式边扫描边求值。
完整代码(来来回回改了N多遍, 支持 ((((3+2))))这种情况) :
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <stack> #include <queue> using namespace std; const int maxOp = 7;//符号的总数 struct Pri //设定运算符优先级 { char ch; //运算符 int pri; //优先级 }lpri[] = {{'=', 0}, {'(', 1}, {'*', 5}, {'/', 5}, {'+', 3}, {'-', 3}, {')', 6}}, rpri[] = {{'=', 0}, {'(', 6}, {'*', 4}, {'/', 4}, {'+', 2}, {'-', 2}, {')', 1}}; int LeftPri(char op)//求左运算符op的优先级 { for(int i = 0; i < maxOp; ++ i) if(lpri[i].ch == op) return lpri[i].pri; } int RightPri(char op)//求右运算符op的优先级 { for(int i = 0; i < maxOp; ++ i) if(rpri[i].ch == op) return rpri[i].pri; } bool IsOp(char ch)//判断符号ch是否为运算符 { if(ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*' || ch == '/') return true; return false; } int Precede(char op1, char op2) //op1和op2运算符优先级的比较结果 { int lPri = LeftPri(op1); int rPri = RightPri(op2); if(lPri == rPri) return 0; else if(lPri < rPri) return -1; else return 1; } void GetTwoFromStack(stack<double>& numStack, double& a, double& b)//从运算数栈中获取两个数,栈顶和次栈顶 { a = numStack.top(); numStack.pop(); b = numStack.top(); numStack.pop(); } double CalFromNumStack(stack<char>& opStack, stack<double>& numStack) //从符号栈提取栈顶符号,利用运算数栈的栈顶和次栈顶进行计算,并把结果压入运算数栈中 { double a, b; char op = opStack.top();//运算符提取 opStack.pop();//退栈 GetTwoFromStack(numStack, a, b);//a,b为栈顶和次栈顶 switch(op) { case '+': numStack.push(b + a); break; case '-': numStack.push(b - a); break; case '*': numStack.push(b * a); break; case '/': numStack.push((b / a)); break; }//switch } float CalFromExp(char* exp) { stack<char> opStack;//符号栈 opStack.push('=');//'='优先级最低 stack<double> numStack;//运算数栈 while(*exp != '\0') { if(!IsOp(*exp)) //如果不是运算符 { int n = 0;//提取数字 while(*exp >= '0' && *exp <= '9') { n = n * 10 + (*exp - '0'); exp ++; } numStack.push(n);//把提取出来的数压入运算数栈 } else { int cmpPri = Precede(opStack.top(), *exp); if(cmpPri == 0) // ')'遇到栈顶'(' { opStack.pop(); exp ++; } else if(cmpPri == -1)// 栈顶运算符优先级小 { opStack.push(*exp); exp ++; } else //栈顶运算符优先级大 { while(Precede(opStack.top(), *exp) == 1) { CalFromNumStack(opStack,numStack); }//while } // exp ++;//扫描下一个字符 }//当前字符是运算符 } while(opStack.top() != '=')//千万不能忘了这个!! { CalFromNumStack(opStack,numStack); } return numStack.top(); } char exp[50]; char postExp[50]; int main() { while(cin >> exp) { cout << "中缀表达式为: " << exp <<endl; //TransToPostExp(exp, postExp);//将算数表达式转化为后缀表达式,比如输入(56-20)/(4+2) ,输出 56#20#-4#2#+/ // cout << "后缀表达式为: " << postExp <<endl; cout << "表达式的值为: " <<CalFromExp(exp) << endl << endl; } return 0; }