先说明一下具体实现的步骤
中缀表达式a + b*c + (d * e + f) * g,其转换成后缀表达式则为a b c * + d e * f + g * +。
1)如果遇到操作数,我们就直接将其输出。
2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) “的情况下我们才弹出” ( “,其他情况我们都不会弹出” ( "。
5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
import java.util.Stack;
public class ReversePolishExpression {
Stack<String> st1 = new Stack<>(); // 存放符号的栈
Stack<String> st2 = new Stack<>(); // 存放数字的栈
String temp = "";
// 从左至右扫描一中缀表达式。
public String scan(String infixExpression) {
// 创建一个字符串数组用来存放中缀表达式
String[] s = infixExpression.split(" ");
for(int i = 0;i < s.length;i++) {
if(s[i].charAt(0) >= 48 && s[i].charAt(0) <= 58) {
temp += s[i];
// 若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
if(i == s.length -1 || s[i+1].charAt(0) < 48 || s[i+1].charAt(0) > 58) {
// 如果当前字符的下一个字符还是字符那么需要拼接
st2.push(temp);
temp = "";
}
// 若读取的是运算符(假定字符串已经校验过非数字即运算符)
}else {
switch(s[i]) {
// 该运算符为左括号"(",则直接存入运算符堆栈
case "(":
st1.push("(");
break;
// 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
case ")":
while(true) {
String temp2 = st1.pop();
if(temp2 != "(") {
st2.push(temp2);
}else {
break;
}
}
break;
// 该运算符为非括号运算符:
default:
//(a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
//(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
if(st1.isEmpty() || priority(s[i]) >= priority(st1.peek()) || st1.peek() == "(") {
st1.push(s[i]);
}
// (c) 若比运算符堆栈栈顶的运算符优先级低,
// 则输出栈顶运算符到操作数堆栈
// 并将当前运算符压入运算符堆栈。
if(priority(s[i]) < priority(st1.peek())) {
st2.push(st1.pop());
st1.push(s[i]);
}
}
}
}
// 当表达式读取完成后运算符堆栈中尚有运算符时
// 则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
while(true) {
if(st1.isEmpty()) {
break;
}
st2.push(st1.pop());
}
String expression = "";
for(String i:st2) {
expression += i;
}
return expression;
}
// 创建一个方法用于比较优先级
public int priority(String sym) {
switch(sym) {
case "+":
return 1;
case "-":
return 1;
case "*":
return 2;
case "/":
return 2;
default:
return 0;
}
}
}