表达式求值
http://www.cnblogs.com/flyingbread/archive/2007/02/03/638932.html
分析用堆栈解析算术表达式的基本方法。给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式。
中缀表达式就是通常所说的算术表达式,比如(1+2)*3-4。
后缀表达式是指通过解析后,运算符在运算数之后的表达式,比如上式解析成后缀表达式就是12+3*4-。这种表达式可以直接利用栈来求解。
中缀表达式翻译成后缀表达式的方法如下:
(1)从左向右依次取得数据ch。
(2)如果ch是操作数,直接输出。
(3)如果ch是运算符(含左右括号),则:
a:如果ch = '(',放入堆栈。
b:如果ch = ')',依次输出堆栈中的运算符,直到遇到'('为止。
c:如果ch不是')'或者'(',那么就和堆栈顶点位置的运算符top做优先级比较。
1:如果ch优先级比top高,那么将ch放入堆栈。
2:如果ch优先级低于或者等于top,那么输出top,反复进行,直到ch优先级高于top或者栈为空,然后将ch放入堆栈。
(4)如果表达式已经读取完成,而堆栈中还有运算符时,依次由顶端输出。
如果我们有表达式(A-B)*C+D-E/F,要翻译成后缀表达式,并且把后缀表达式存储在一个名叫output的字符串中,可以用下面的步骤。
(1)读取'(',压入堆栈,output为空
(2)读取A,是运算数,直接输出到output字符串,output = A
(3)读取'-',此时栈里面只有一个'(',因此将'-'压入栈,output = A
(4)读取B,是运算数,直接输出到output字符串,output = AB
(5)读取')',这时候依次输出栈里面的运算符'-',然后就是'(',直接弹出,output = AB-
(6)读取'*',是运算符,由于此时栈为空,因此直接压入栈,output = AB-
(7)读取C,是运算数,直接输出到output字符串,output = AB-C
(8)读取'+',是运算符,它的优先级比'*'低,那么弹出'*',压入'+",output = AB-C*
(9)读取D,是运算数,直接输出到output字符串,output = AB-C*D
(10)读取'-',是运算符,和'+'的优先级一样,因此弹出'+',然后压入'-',output = AB-C*D+
(11)读取E,是运算数,直接输出到output字符串,output = AB-C*D+E
(12)读取'/',是运算符,比'-'的优先级高,因此压入栈,output = AB-C*D+E
(13)读取F,是运算数,直接输出到output字符串,output = AB-C*D+EF
(14)原始字符串已经读取完毕,将栈里面剩余的运算符依次弹出,output = AB-C*D+EF/-
计算算术表达式
当有了后缀表达式以后,运算表达式的值就非常容易了。可以按照下面的流程来计算。
(1)从左向右扫描表达式,一个取出一个数据data
(2)如果data是操作数,就压入堆栈
(3)如果data是操作符,就从堆栈中弹出此操作符需要用到的数据的个数,进行运算,然后把结果压入堆栈
(4)如果数据处理完毕,堆栈中最后剩余的数据就是最终结果。
比如我们要处理一个后缀表达式1234+*+65/-,那么具体的步骤如下。
(1)首先1,2,3,4都是操作数,将它们都压入堆栈
(2)取得'+',为运算符,弹出数据3,4,得到结果7,然后将7压入堆栈
(3)取得'*',为运算符,弹出数据7,2,得到数据14,然后将14压入堆栈
(4)取得'+',为运算符,弹出数据14,1,得到结果15,然后将15压入堆栈
(5)6,5都是数据,都压入堆栈
(6)取得'/',为运算符,弹出数据6,5,得到结果1.2,然后将1.2压入堆栈
(7)取得'-',为运算符,弹出数据15,1.2,得到数据13.8,这就是最后的运算结果
1 class ComputeExpr 2 { 3 public: 4 string transPosExpr(string s); //将中缀表达式转化成后缀表达式,比如(1+2)*3-4转化成12+3*4- 5 double calcExpr(string s); //计算后缀表达式的值 6 private: 7 int getPriority(char ch); //获取操作符的优先级 8 bool isOperator(char ch); //判断是否为操作符或者操作数 9 double calc(double a,char ch, double b); 10 }; 11 12 string ComputeExpr::transPosExpr(std::string s) 13 { 14 string ret; 15 stack<char> stkOper; 16 int len = s.length(); 17 for (int i=0; i<len; i++) 18 { 19 if (!isOperator(s[i])) //如果是操作数,直接输出 20 { 21 ret += s[i]; 22 } 23 else if (s[i]=='(') //如果是'(',将它放入堆栈中 24 { 25 stkOper.push('('); 26 } 27 else if (s[i]==')') //如果是')' 28 { 29 while(!stkOper.empty()) //不停地弹出堆栈中的内容,直到遇到'(' 30 { 31 char topChar = stkOper.top(); 32 stkOper.pop(); 33 if (topChar=='(') 34 { 35 break; 36 } 37 ret += topChar; //将堆栈中弹出的内容放入 38 } 39 } 40 else //既不是'(',也不是')',是其它操作符,比如+, -, *, /之类的 41 { 42 if (!stkOper.empty()) 43 { 44 do 45 { 46 char topChar = stkOper.top(); 47 stkOper.pop(); 48 if (getPriority(s[i]) > getPriority(topChar))//如果栈顶元素的优先级小于读取到的操作符 49 { 50 stkOper.push(topChar); //将栈顶元素放回堆栈 51 stkOper.push(s[i]); //将读取到的操作符放回堆栈 52 break; 53 } 54 else //如果栈顶元素的优先级比较高或者两者相等时 55 { 56 ret += topChar; 57 if (stkOper.empty()) 58 { 59 stkOper.push(s[i]); //将读取到的操作符压入堆栈中 60 break; 61 } 62 } 63 } 64 while (!stkOper.empty()); 65 } 66 else //如果堆栈为空,就把操作符放入堆栈中 67 { 68 stkOper.push(s[i]); 69 } 70 } 71 } 72 while(!stkOper.empty()) //将堆栈中剩下的操作符输出 73 { 74 ret += stkOper.top(); 75 stkOper.pop(); 76 } 77 return ret; 78 } 79 80 double ComputeExpr::calcExpr(std::string s) 81 { 82 int len = s.length(); 83 stack<double> stk; 84 for (int i=0; i<len; i++) 85 { 86 if (!isOperator(s[i])) //如果是操作数,直接压入栈 87 { 88 stk.push(s[i]-'0'); 89 } 90 else //如果是操作符,就弹出两个数字来进行运算 91 { 92 double a = stk.top(); 93 stk.pop(); 94 double b = stk.top(); 95 stk.pop(); 96 double t = calc(b,s[i],a); 97 stk.push(t); 98 } 99 } 100 return stk.top(); 101 } 102 103 int ComputeExpr::getPriority(char ch) 104 { 105 int priority = 0; 106 switch(ch) 107 { 108 case '+': 109 priority = 1; 110 break; 111 case '-': 112 priority = 1; 113 break; 114 case '*': 115 priority = 2; 116 break; 117 case '/': 118 priority = 2; 119 break; 120 default: 121 priority = 0; 122 break; 123 } 124 return priority; 125 } 126 127 bool ComputeExpr::isOperator(char ch) 128 { 129 const int MaxOperatorNum = 6; 130 const char a[MaxOperatorNum] = {'+','-','*','/','(',')'}; 131 for (int i=0; i<MaxOperatorNum; i++) 132 { 133 if (ch == a[i]) 134 { 135 return true; 136 } 137 } 138 return false; 139 } 140 141 double ComputeExpr::calc(double a,char ch, double b) 142 { 143 double res; 144 switch(ch) 145 { 146 case '+': 147 res = a+b; 148 break; 149 case '-': 150 res = a-b; 151 break; 152 case '*': 153 res = a*b; 154 break; 155 case '/': 156 res = a/b; 157 break; 158 } 159 return res; 160 }