- 其实逆波兰表达式不难,更是栈的一个经典问题。网上关于逆波兰表达式的blog也很多。本人也曾经受到这些好blog的帮助。只不过,别人做过的事,毕竟不是自己做过的。因此,为了一步一步脚踏实地。我也写一篇blog来讲讲逆波兰表达式核心思路。
- 逆波兰表达式主要是两个部分:1、中缀转后缀。2、后缀表达式求值
- 中缀表达式,后缀表达式这些名词可能对于菜鸟程序员来说,是个新鲜的词语。中缀表达式就是我们生活中经常写的“1+2”这种式子,那聪明的你肯定可以联想到后缀和前缀,具体是什么了。不错,前缀就是“+12”,
后缀就是“12+“。 - 那现在先从第一步开始:如何从中缀表达式变为后缀表达式。 就拿一个简单的例子: (1 + 2) * 3 来做个例子。
从字符串的头遍历到结尾,第一个遇到了左括号,这个时候,我们先压进栈里,那么栈里的状态如下 那么现在继续迭代
继续
现在遇到了1,那么现在后缀表达式就为 : 1
终于遇到运算符了,那这个时候呢,就应该开始做一些处理。运算符进栈前,得保证进去后,栈顶的运算符的运算优先级是最高的,举个例子,栈里的元素如果是这个样子 ( * , 你要把+号压进去,就得把给pop出来,来保证栈顶的+号是目前运算优先级最高的,所以,当前栈里的状态为:
好,我们继续吧
遇到了数字,那么就先放进后缀表达式吧,现在的后缀表达式:1 2
现在,遇到右括号了哦,那么,这个时候的规则呢,就是把目前栈里的元素都pop出来,直到遇到左括号
所以,这个时候的后缀表达式为:1 2 +(左括号pop出去就丢弃可以了,不用加入后缀表达式)
继续
遇到运算符,没什么好说的啦,老规矩
继续
这里也没什么特别的,加入后缀表达式吧,此时后缀表达式为:* 1 2 + 3 *
到这里,字符串也迭代完了,好累哟,不过还没大功告成噢,别忘了栈里还有一个残留的运算符,别忘了把它也给pop出去,那么最后的结果:1 2 + 3 就是后缀表达式了啦。
下面就直接上代码吧
#include <iostream>
#include <string>
#include <stack>
using namespace std;
class reversePolishNotation {
public:
reversePolishNotation(){
}
//中缀转后缀表达式
string getSuffixExpression(string orginalExpression) {
int length = orginalExpression.length(); //原中缀表达式的长度
stack<char> stk; //存放运算符
string res = ""; //记录后缀表达式
for (int i = 0; i < length; i++) {
char c = orginalExpression[i];
if (c == '(') {//左括号 的时候就压栈吧
stk.push(c);
} else if (c == ')') {//右括号时,就一直pop,直到遇到左括号
while(!stk.empty() && stk.top() != '(') {
res += stk.top();
stk.pop();
}
if (!stk.empty()) stk.pop();//当然左括号这个时候已经没有用处,也pop
} else if (isOpeartor(c)) {//栈顶的运算符的优先级必定是栈内最高的
while(!stk.empty() && stk.top() != '('&&priority(stk.top()) >= priority(c)) {
res += stk.top();
stk.pop();
}
stk.push(c);
} else if (c == ' ') {
continue;
} else {
string num = "";
while(isNumber(c)) {
num += c;
c = orginalExpression[++i];
}
num += '#';//#这个是我为了辨别数字而设置的一个标记。
res += num;
i--;
}
}
while(!stk.empty()) {//最后还会有运算符在栈中,别忘了pop出来
res += stk.top();
stk.pop();
}
return res;//大功告成
}
private:
//判断运算符的优先级
int priority(char c) {
if ('%' == c || '*' == c || '/' == c) return 1;
if ('+' == c || '-' == c) return 0;
}
//判断是否是运算符
bool isOpeartor(char c) {
if ('/' == c || '*' == c || '+' == c || '-' == c) return true;
return false;
}
//判断是不是数字
bool isNumber(char c) {
if (c >= '0' && c <= '9') return true;
return false;
}
//stoi这个函数貌似在c++11已经有了,只不过是我的编译器没有c++11版本,所以自己手写了一个,其实就几行代码。
int stoi(string str) {
int res = 0;
for (int i = 0; i < str.length(); i++) {
res *= 10;
res += (str[i] - '0');
}
return res;
}
};
int main() {
//一个小测试
reversePolishNotation s;
string str = s.getSuffixExpression("122-2+3*2+1/2");
cout<<str<<endl;//122#2#-3#2#*+1#2#/+
return 0;
}
今天就到这吧!共勉