一年多未更新博客了,此贴纯刷屏用。前段做培训留的题目,自己作了下,感觉蛮简单的代码测的时候还是有不少坑,只做了整数版本,懒得再弄了。
import java.util.ArrayList;
import java.util.Stack;
/**
* 逆波兰表达式实现四则运算
*
* @author Duanhengbin
*
*/
public class Exercise02 {
// 四则运算式中的符号
static String OPERATORS = "+-*/()";
/**
* 根据输入的中缀表达式列表计算
*
* @param aPstfix
* @return
*/
public static int RpnComputer(String expression) {
Stack<String> stack = new Stack<String>();
int num1, num2, result;
num1 = num2 = result = 0;
ArrayList<String> aPstfix = createPstfix(expression);
for (String cell : aPstfix) {
// 数字的场合
if (OPERATORS.indexOf(cell) == -1) {
stack.push(cell);
// 符号的场合
} else {
// TODO: 支持带小数的数字计算
num1 = Integer.parseInt(stack.pop());
num2 = Integer.parseInt(stack.pop());
switch (cell) {
case "+":
result = num2 + num1;
break;
case "-":
result = num2 - num1;
break;
case "*":
result = num2 * num1;
break;
case "/":
result = num2 / num1;
break;
default:
// TODO: throw Exception
}
stack.push(Integer.toString(result));
}
}
return result;
}
/**
* 根据输入表达式字符串生成后缀表达式列表
*
* @param s
* @return
*/
private static ArrayList<String> createPstfix(String s) {
String[] cells = extractArrayFromExp(s);
ArrayList<String> results = new ArrayList<String>();
Stack<String> stack = new Stack<String>();
for (String cell : cells) {
if (OPERATORS.indexOf(cell) == -1) { // 数字的场合
results.add(cell);
} else { // 符号的场合
if (cell.equals(")")) {
// 待入栈“)”时,只出不入
results.addAll(popStack(stack, cell));
} else if (stack.isEmpty() || stack.peek().equals("(") || cell.equals("(") || "*/".contains(cell) && "+-".contains(stack.peek())) {
// 这些为只入不出的情况
stack.push(cell);
} else {
// 其他情况 先出后入
if ("*/".contains(cell)) {
results.add(stack.pop());
} else {
results.addAll(popStack(stack, cell));
}
stack.push(cell);
}
}
}
if (!stack.isEmpty()) {
results.addAll(popStack(stack, ""));
}
return results;
}
/**
* 返回从当前栈中出栈且需要加入到表达式的符号列表
*
* @param stack
* @return
*/
private static ArrayList<String> popStack(Stack<String> stack, String inSign) {
ArrayList<String> rtn = new ArrayList<String>();
// 将遇到“(”为止所有符号出栈
while (!stack.isEmpty() && !"(".equals(stack.peek())) {
rtn.add(stack.pop());
}
// 入栈“)”时,将“(”出栈
if (inSign.equals(")")) {
stack.pop();
}
return rtn;
}
/**
* 先将符号两侧增加空格,再替换多个空格为一个空格,最后用空格切分,将表达式拆分成数字与符号列表
*
* @param s
* @return
*/
private static String[] extractArrayFromExp(String s) {
String sOperator = null;
// 在符号前后添加空格
for (int i = 0; i < OPERATORS.length(); i++) {
sOperator = OPERATORS.substring(i, i + 1);
s = s.replaceAll("\\" + sOperator, " " + sOperator + " ");
}
// 将多个空白字符:[\t\n\x0B\f\r] 替换为一个空格 注意这里正则简记法\s
s = s.replaceAll("[\\s]+", " ");
return s.trim().split(" ");
}
}
测试代码
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import exercise.Exercise02;
@RunWith(Parameterized.class)
public class Exercise02Test {
private String exep;
private String result;
@Parameters
public static Collection<String[]> data() {
return Arrays.asList(new String[][] {
{ "9 + (3 -1)* 3+10/2 ", "20" },
{ "((((2-3)*(8/2-1))))", "-3" },
{ "((1+2+3) * 2)-10+4/2*3 ", "8" },
{ "(1+2+3+4*5*6/2-9)", "57" },
{ " (1*2*3*8-5*6/2/3/5-9)", "38" },
{ " (1*2*3*6/9/2*10-(1+2)*4) ", "8" },
{ "10-9/3+3*(2/(1/1))", "13" }
});
}
public Exercise02Test(String exep, String result) {
this.exep = exep;
this.result = result;
}
@Test
public void testRpnComputer() {
assertEquals(result, String.valueOf(Exercise02.RpnComputer(exep)));
}
}