前言:
公司软件开发的新特性,里面有部分代码读起来很生涩,一直在入栈出栈,搞的一头雾水,后来问了公司的SE大牛(膜拜),说这个是逆波兰式,当时就懵逼了,后来wiki了下,发现原来就是后缀表达式,想想当年刷ACM还刷过这类题,不过太久远了,早就忘记了!我们平时数学中接触到最多的是中缀表达式:1+2*(1+5)/3,这种表达式非常适合人去阅读,但是不适合用数据结构进行表示用于计算,而后缀表达式就可以用非常简单的入栈出栈来进行计算。
1、波兰式(中缀表达式)转化为逆波兰(后缀表达式)
先看一段伪代码
BEGIN:
1.将波兰式进行分割,存放到数组中element[]中
2.从左向右扫描波兰式,执行下面的操作;
3.if (当扫描到的elemen[i]为数值时)
将element[i]添加到输出串str中;
4.if (当扫描到的elemen[i]是括号'('时)
将elemen[i] push到stack中;
5.while (当扫描到的elemen[i]是操作符op时)
if (stack为空 或 stack栈顶为'(' 或 扫描到的运算符优先级比栈顶操作符高,不包括相等)
将elemen[i] push 到stack中;
break;
else
stack出栈保存到字符串str中
6.if (当扫描到的elemen[i]是闭括号')')
stack中运算符逐个出栈并输出到str中,直到遇到开括号'(';
将'('出栈并丢弃;
7.返回第2.步
8.while (扫描结束而栈中还有运算符)
运算符出栈并加到字符串str中
END
直接上代码:
public class ReversePolish {
private Set<String> ele = new HashSet<>();
private ReversePolish() {
ele.add("+");
ele.add("-");
ele.add("*");
ele.add("/");
ele.add("(");
ele.add(")");
}
public boolean isOp(String element) {
if (ele.contains(element))
return true;
else
return false;
}
public int priority(String op) {
if (op.equals("+") || op.equals("-"))
return 1;
if (op.equals("*") || op.equals("/"))
return 2;
else
return 0;
}
public String reversePolish(String[] element, Stack<String> stack) {
StringBuffer str = new StringBuffer("");
for (int i = 0; i < element.length; i++) {
if (!isOp(element[i])) {
str.append(element[i] + " ");
continue;
}
while (true) {
if (stack.empty() || element[i].equals("(") || priority(element[i]) > priority(stack.peek())) {
stack.push(element[i]);
break;
}
String elementStr = stack.pop();
if (elementStr.equals("(")) {
break;
}
str.append(elementStr+" ");
}
}
while (!stack.empty()) {
str.append(stack.pop()+" ");
}
return str.toString().trim();
}
}
2.逆波兰式运算
上面的代码展示的是将波兰式转化为逆波兰式,而逆波兰式,就可以通过非常简单的出栈入栈来进行计算
比如波兰式1+2*3/6转化为逆波兰式为1 2 3 * 6 / +,逆波兰的计算就通过下面的方法
同样上一段伪代码
BEGIN:
1.将逆波兰式进行分割,存放到数组中element[]中
2.从左向右扫描波兰式,执行下面的操作;
3.if(扫描到elemen[i]为数值)
将elemen[i]存到stack栈中
4.if(扫描到elemen[i]为运算符时)
将stack中取出两个数,进行elemen[i]运算符的操作
5.返回到2.步
6.取出stack的数为逆波兰式的运算结果
END
上代码:
public class CalReversePolish {
private double calculate(String op, double val1, double val2) {
if (op.equals("+"))
return val1 + val2;
if (op.equals("-"))
return val1 - val2;
if (op.equals("/"))
return val2 / val1;
if (op.equals("*"))
return val1 * val2;
throw new RuntimeException("wrong operator");
}
public double calReversePolish(String polish) {
Stack<Double> stack = new Stack<>();
String[] element = polish.split(" ");
for (int i = 0; i < element.length; i++) {
if (element[i].equals("+") || element[i].equals("-") || element[i].equals("*") || element[i].equals("/")) {
stack.push(calculate(element[i], stack.pop(), stack.pop()));
continue;
}
stack.push(Double.parseDouble(element[i]));
}
return stack.pop();
}
}