标签:
分析:
中缀表达式的操作符以中缀的形式处于操作数的中间。
若创建一个数字栈,一个运算符栈,并将一个中缀表达式从左至右压入栈这两个栈中。先向数字栈压入一个数字,再向运算符栈压入一个运算符,接着向数字栈压入数字。此时数字栈中有两个元素,字符栈中有一个元素。
当开始读到第二个运算符时就判断当前准备压入运算符与之前已在栈中运算符的优先级顺序,若栈顶的运算符优先顺序大于或等于当前即将压入的运算符,则弹出两个数字栈中的元素和一个运算符栈中的元素进行运算,将结果重新压回数字栈中,然后将当前的读到的运算符压入数字栈中。(例如:数字栈中含有4(栈顶)3,运算符栈中含有+(栈顶),读到*时,则先弹出4,3,和+,4+3进行计算得到7,并将7压入数字栈,然后将*压入栈中,完成后数字栈中含有7(栈顶),运算符栈中含有*(栈顶)
若优先级小于当前运算符,则直接将当前运算符压入栈中。(例如:运算符中存在+,当读到*时,直接压入栈中,不进行运算。)
因此数字栈中的元素至多有3个,操作符栈中的元素至多2个,且每次操作完成后,数字栈中的元素一定比操作符栈的元素多一个。
当对表达式读取完成后,对栈进行运算(数字栈弹出两个数字,操作符栈弹出一个操作符,并将运算结果压回数字栈中),直至操作符栈位空结束,数字栈中剩余的元素即为该中缀表达式的运算结果。
对于(),可以将其之间的内容视作一个独立式,独立于它前后的运算符。当读到(时,将其直接压入栈;读到)时,将()之间的表达式进行计算,得到一个数字,最终()之间的内容就等价于一个数字。
代码:
1 #include "stdafx.h" 2 #include <stack> 3 #include <string> 4 #include <iostream> 5 #include <stdio.h>//用于double与string的转换 6 using namespace std; 7 double calExp(string); 8 void calStack(stack<double>&, stack<char>&); 9 int _tmain(int argc, _TCHAR* argv[]) 10 { 11 string infixExp;// 中缀表达式 12 for (;;){ 13 cout << "输入一个合法的表达式,无输入则退出" << endl; 14 getline(cin, infixExp); 15 if (infixExp == "")break; 16 cout << "计算结果为:" << calExp(infixExp) << endl; 17 } 18 } 19 void calStack(stack<double>& numStack, stack<char>& opStack){//弹出两个数字和一个符号进行一次运算,并将得到结果压入数字栈中. 20 double num2 = numStack.top(); 21 numStack.pop(); 22 double num1 = numStack.top(); 23 numStack.pop(); 24 double num = 0;//运算结果 25 switch (opStack.top()) 26 { 27 case‘+‘: 28 num = num1 + num2; 29 break; 30 case‘-‘: 31 num = num1 - num2; 32 break; 33 case‘*‘: 34 num = num1*num2; 35 break; 36 case‘/‘: 37 num = num1 / num2; 38 break; 39 } 40 numStack.push(num); 41 opStack.pop(); 42 } 43 double calExp(string exp){ 44 char token;//exp中读取的位置 45 stack<double>numStack;//数字栈 46 stack <char> opStack;//运算符栈 47 double number1 = 0, number2 = 0;//数字栈弹出的进行两个运算的数字 48 for (int i = 0; i < exp.length(); i++){//按顺序扫描exp中所有的元素 49 token = exp[i]; 50 switch (token) 51 { 52 case ‘ ‘: break; 53 case ‘+‘:case‘-‘: 54 if (numStack.size() < 2 || opStack.size()<1 ||opStack.top()==‘(‘){ 55 opStack.push(token); 56 } 57 else 58 { 59 calStack(numStack, opStack); 60 opStack.push(token); 61 } 62 break; 63 case‘*‘:case‘/‘://若遇到*/,优先级最高 直接压入栈中 64 if (numStack.size() < 2 || opStack.size()<1 || opStack.top() == ‘+‘ || opStack.top() == ‘-‘||opStack.top() == ‘(‘){ 65 opStack.push(token); 66 } 67 else 68 { 69 calStack(numStack, opStack); 70 opStack.push(token); 71 } 72 break; 73 case‘(‘: 74 opStack.push(token); 75 break; 76 case‘)‘: 77 for (;;){//将()中的元素进行运算 78 if (opStack.top() == ‘(‘){ 79 opStack.pop(); 80 break; 81 } 82 calStack(numStack, opStack); 83 } 84 break; 85 default: 86 string inNum;//压入栈中的数字 87 inNum.append(1,token);//先将第一个数字存入inNum 88 for (;;){//读取多位的数字 89 if (!isalnum(exp[i + 1]) && (exp[i + 1])!=‘.‘)break;//非数字时停止(不包括小数点) 90 i++; 91 token = exp[i]; 92 inNum.append(1,token);// 93 } 94 double number=atof(inNum.c_str());//将字符串转换为数字压入栈中 95 numStack.push(number); 96 break; 97 } 98 } 99 for (;;){// 100 if (opStack.empty())break; 101 calStack(numStack, opStack); 102 } 103 return numStack.top(); 104 }
运行结果:
存在的问题:
本方法未考虑未知数(字母,如x,y),输入未知数时运算将出现错误。
未进行错误检测,当输入的中缀表达式不规范时,将会报错。
标签:
原文地址:http://www.cnblogs.com/Quantum-Xyx/p/4989930.html