逆波兰式,也叫做后缀表达式,每一运算符都置于其运算对象之后,故称为后缀表示。值得注意的是,后缀表达式没有优先级的概念,会按照运算符从左向右进行运算。这种理解这对于把普通表达式转换为后缀表达式很重要。比如下面的式子:
a+b ---> a,b,+
a+(b-c) ---> a,b,c,-,+
a+(b-c)*d ---> a,b,c,-,d,*,+
a+d*(b-c)--->a,d,b,c,-,*,+
a=1+3 ---> a=1,3 +
实现代码如下:
/**
* 计算后缀表达式,操作很简单,就是入栈和出栈进行计算
* @param tokens 后缀表达式
*/
public static int evalRPN(String[] tokens) {
int returnValue = 0;
String operators = "+-*/";
Stack<String> stack = new Stack<String>();
for (String t : tokens) {
//如果解析到的字符不是运算符就将当前的值push到栈里,
if (!operators.contains(t)) {
//push~
stack.push(t);
} else {
//如果解析到的是运算符,那么就可以进行计算了
//能够保证计算结果的正确性的前提是有两个保证:
//1、后缀表达式的特性:运算符是紧跟着操作数后面的
//2、栈的特点:栈是先进后出的特点,先push进去的元素,在pop出一个元素时,取出的是最后push进去的元素,注意,pop出一个元素后,该元素就不存在栈中了
//基于以上两点,可以形成基本思路:对后缀表达式进行遍历,如果遇到的不是运算符那么就push到栈中,如果遇到运算符就将前面的两个数字取出运算
//由此可见,如果一个表达式的第一个运算符的前面只有一个数字,这样的表达式不应该算是后缀表达式
int a = 0, b = 0;
if (!stack.empty()) {
a = Integer.valueOf(stack.pop());
}
if (!stack.empty()) {
b = Integer.valueOf(stack.pop());
}
//当前解析到的运算符,本例中的运算符是用一个字符串表示的四种基本运算
int index = operators.indexOf(t);
//将计算后的值再次push到栈中
switch (index) {
case 0:
stack.push(String.valueOf(a + b));
break;
case 1:
stack.push(String.valueOf(b - a));
break;
case 2:
stack.push(String.valueOf(a * b));
break;
case 3:
stack.push(String.valueOf(b / a));
break;
}
}
}
//栈顶上的元素就是累计算的结果
returnValue = Integer.valueOf(stack.pop());
return returnValue;
}
以上算法是摘自:http://www.programcreek.com/2012/12/leetcode-evaluate-reverse-polish-notation/ 我只加了两个if判断。
后缀表达式,运算及其简洁,只需要通过入栈和出栈就可以完成简单运算,但是我们平时使用的都是普通表达式,因此下面来实现将普通表达式转换为后缀表达式的算法:
/**
* 优先级比较
* @param operator1 比较值
* @param operator2 被比较值
* @return 小于等于返回false,大于返回true
*/
public static boolean comparePrior(String operator1, String operator2) {
if("(".equals(operator2)) {
return true;
}
if ("*".equals(operator1) || "/".equals(operator1)) {
if ("+".equals(operator2) || "-".equals(operator2)) {
return true;
}
}
return false;
}
/**
* 转为后缀表达式:
* 1、如果是"("直接压入stack栈。
* 2、如果是")",依次从stack栈弹出运算符加到数组newExpressionStrs的末尾,值到遇到"(";
* 3、如果是非括号,比较扫描到的运算符,和stack栈顶的运算符。如果扫描到的运算符优先级高于栈顶运算符则,
* 把运算符压入栈。否则的话,就依次把栈中运算符弹出加到数组newExpressionStrs的末尾,直到遇到优先级低于扫描到的运算符或栈空,
* 并且把扫描到的运算符压入栈中。就这样依次扫描,知道结束为止。如果扫描结束,栈中还有元素,则依次弹出加到数组newExpressionStrs的末尾,
* 就得到了后缀表达式。
* @param expressionStrs
* @return
*/
public static String[] toSuffixExpression(String[] expressionStrs) {
//新组成的表达式
List<String> newExpressionStrs = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
for (int i = 0; i < expressionStrs.length; i++) {
// 如果是左括号,则直接
if ("(".equals(expressionStrs[i])) {
stack.push(expressionStrs[i]);
} else if ("+".equals(expressionStrs[i]) || "-".equals(expressionStrs[i]) || "*".equals(expressionStrs[i]) || "/".equals(expressionStrs[i])) {
if (!stack.empty()) {
String s = stack.pop();
//如果栈值优先级小于要入栈的值,则继续压入栈
if(comparePrior(expressionStrs[i], s)) {
stack.push(s);
} else {
//否则取出值
newExpressionStrs.add(s);
}
}
stack.push(expressionStrs[i]);
} else if (")".equals(expressionStrs[i])) { //如果是")",则出栈,一直到遇到"("
while (!stack.empty()) {
String s = stack.pop();
if (!"(".equals(s)) {
newExpressionStrs.add(s);
} else {
break;
}
}
} else {
newExpressionStrs.add(expressionStrs[i]);
}
}
while (!stack.empty()) {
String s = stack.pop();
newExpressionStrs.add(s);
}
return newExpressionStrs.toArray(new String[0]);
}