在程序设计中,可能碰到需要对字符串数学表达式求值的问题,常用的方法是解析表达式,生成二叉树,然后进行计算。编译器就是使用这种方法来解析程序中的表达式的。这种方法实现起来有点难度,需要考虑运算符的优先级,括号的配对,堆栈的使用等等。我们正常情况下看到的数学表达式如果用二叉树遍历的话,恰好是中序遍历,故叫做中序表达式。除此之外,还有前序表达式,后序表达式。如:a+b+c(中序),++abc(前序),ab+c+(后序),如果表达式含有×,/,()等就更复杂了。
后缀表达式也称逆波兰表达式 因其使表达式求值变得轻松,所以被普遍使用。
没有括号的逆波兰式求解:
中缀表达式转换为逆波兰式:
将一个普通的中序表达式转换为逆波兰表达式的一般算法是(没有括号):
1、首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
2、读入一个中缀表达式,为了方便起见,可在其最右端追加一个最低优先级运算符(如:#号)。(这样做的目的是,最后读入#号运算符时将运算符栈中所有运算符都输出)。
3、从左至右扫描该中缀表达式,如果当前字符是数字,则分析到该数字串的结束,并将该数字串直接输出。
4、如果不是数字,该字符则是运算符,此时需比较该运算符与运算符栈顶运算符的优先关系:
(1)、若该运算符优先级高于栈顶运算符优先级别(或栈为空),则直接将该运算符压入运算符栈中;
(2)、若该运算符优先级小于或等于此运算符栈顶的运算符,则弹出栈顶运算符并输出,重复比较、输出,直到栈为空或该运算符优先级高于栈顶运算符,然后将该运算符入栈。
5、重复上述操作(3)-(4)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,输出结果便是中缀表达式转化为逆波兰表示的简单算术表达式。
有括号的时候:
1.首先构造一个运算符栈,在这个栈中越往栈顶运算符的优先级越高。
2.构造一个数字栈,主要用来存放数字
3.读入一个中缀表达式,从左至右扫描表达式,如果字符是数字,则分析该数字串的结束,并将该字符串入数字栈
4.如果不是数字:
1.如果是左括号,直接入符号栈
2.如果是右括号,那么让符号栈中的符号依次出栈并依次进入数字栈直到遇到第一个右括号,并让该右括号出栈
3.如果是运算符,并且运算符的优先级高于栈顶元素,直接入符号栈
4.如果是运算符,并且优先级低于或者等于栈顶元素,那么运算符栈依次出栈并依次进入数字栈,直到运算符栈顶第一次出现比当前要入栈的运算符优先级低的符号,或者遇到第一个左括号,或者符号栈为空,那么当前符号入栈
5.如果是数字,直接入数字栈
6.最后数字栈中元素依次进入符号栈
最后符号栈中的元素依次出栈就是逆波兰式
项目代码github地址:https://github.com/ImTangYun/comprehensive/tree/master/C%2B%2B/algorithm/Reverse_Polish
- Source Code
// // 中序表达式(普通常见的运算表达式)转换成逆波兰式 本算法中包括了括号 // #include <stdio.h> #include <string> #include <stack> #include <unordered_map> using std::unordered_map; using std::stack; using std::string; string MtoReverse(const string &str) { if (str.size() == 0) return ""; unordered_map<char, int> pre; pre[‘+‘] = 0; pre[‘-‘] = 0; pre[‘*‘] = 1; pre[‘/‘] = 1; stack<char> s1; stack<char> s2; for (int i = 0; i < str.size(); ++i) { if (pre.find(str[i]) != pre.end()) { while (!s2.empty() && s2.top() != ‘(‘ && pre[str[i]] <= pre[s2.top()]) { s1.push(s2.top()); s2.pop(); } s2.push(str[i]); } else if (str[i] == ‘(‘){ s2.push(str[i]); } else if (str[i] == ‘)‘) { while (s2.top() != ‘(‘) { s1.push(s2.top()); s2.pop(); } s2.pop(); } else { s1.push(str[i]); } } while (!s1.empty()) { s2.push(s1.top()); s1.pop(); } string ret; while (!s2.empty()) { ret += s2.top(); s2.pop(); } return ret; } int main() { string str = "a+b-c*x/(b+a)"; printf("%s\n", MtoReverse(str).c_str()); return 0; }