目录
一.算法思想
将一个普通的中缀表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为存放结果(逆波兰式)的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈。
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
二.代码实现
public static void main(String[] args) {
//中缀表达式,这里以#作为最低优先级的运算符结束
String infixExpression = "11 + 12 * ( 19 - 125 )#";
//1.将中缀表达式拆分成数字和符号字符串 11 , + , 12 ...
List<String> s0 = getInfixList(infixExpression);
System.out.println(s0);
Stack<String> stack = handleInfixList(s0);
System.out.println(stack);
}
public static Stack<String> handleInfixList(List<String> s0) {
//存储运算符的栈S1
Stack<String> s1 = new Stack();
//默认放入优先级最低的运算符#
s1.push("#");
//存放后缀表达式的栈
Stack<String> s2 = new Stack();
//(5)重复上面的1~4步,直至处理完所有的输入字符。
for (String s : s0) {
switch (s) {
//(3)若取出的字符是“(”,则直接送入S1栈顶。
case "(":
s1.push(s);
break;
//(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
case ")":
while (!"(".equals(s1.peek())) {
s2.push(s1.pop());
}
//将左括号丢弃消除小括号
s1.pop();
break;
case "+":
case "-":
case "*":
case "/":
/**
* (2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈,
* 否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
*/
while (true) {
if (!"#".equals(s1.peek()) && getPriority(s) <= getPriority(s1.peek())) {
s2.add(s1.pop());
} else {
s1.push(s);
break;
}
}
break;
//(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
case "#":
while (!"#".equals(s1.peek())) {
s2.push(s1.pop());
}
break;
default:
//(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈。
if (s.matches("\\d+")) {
s2.push(s);
}
break;
}
}
return s2;
}
/**
* 拆分中缀字符串
*
* @param s
* @return
*/
public static List<String> getInfixList(String s) {
List<String> list = new ArrayList<>();
//保存字符 放入c;
char c;
for (int i = 0; i < s.length(); ) {
c = s.charAt(i);
//c不是数字:直接进栈
if (c < '0' && c > '9') {
list.add(c + "");
i++;
} else {//c是数字:数字拼接,继续往下遍历直到不是数字
//多位数拼接
String tmp = c + "";
i++;
for (; i < s.length(); i++) {
c = s.charAt(i);
if (c >= '0' && c <= '9') {
tmp += c;
continue;
}
break;
}
list.add(tmp.trim());
}
}
return list;
}
/**
* 获取运算符的优先级
*
* @param pop
* @return
*/
private static int getPriority(String pop) {
int lev = 0;
switch (pop) {
case "#":
lev = -2;
break;
case "+":
case "-":
lev = 1;
break;
case "*":
case "/":
lev = 2;
break;
case "(":
lev = -1;
break;
default:
break;
}
return lev;
}