中序表达式对我们而言是很直观的(我们平时接触的就是这个),但计算机处理起来比较麻烦(括号、优先级之类的),前序和后序表达式中没有括号,而且在计算中只需单向扫描,不需要考虑运算符的优先级。如2*3/(2-1)+3*(4-1)
前序表达式就是前缀表达式,不含括号的算术表达式,而且它是将运算符写在前面,操作数写在后面的表达式,例如:+/*23-21*3-4,也称为“波兰式”。
后序表达式与前序表达式扫描方式正好相反,例如:23*21-/341-*+。
用两个栈实现中序表达式求值,表达式中只支持int( 但是计算的结果可能是float)
InfixExpr expr = new InfixExpr("2+3*4+5");
Assert.assertEquals(19, expr.evaluate(), 0.001f);
下面展示了在栈中具体的操作过程
下面是具体的实现代码:
public class InfixExpr { String expr = null; public InfixExpr(String expr) { this.expr = expr; } public float evaluate() { char[] ch = expr.toCharArray(); MyStack stackOfTocken = new MyStack(); MyStack stackOfNumber = new MyStack(); for (int i = 0; i < ch.length; i++) { if (Character.isDigit(ch[i])) { int tmp = Integer.parseInt("" + ch[i]); while (i < ch.length - 1 && Character.isDigit(ch[++i])) { tmp = tmp * 10 + Integer.parseInt("" + ch[i]); } System.out.println(tmp); stackOfNumber.push(tmp); } if (ch[i] == ‘+‘ || ch[i] == ‘-‘ || ch[i] == ‘*‘ || ch[i] == ‘/‘) { stackOfTocken.push(ch[i]); } if (!(stackOfTocken.isEmpty()) && (char) stackOfTocken.peek() == ‘*‘) { int tmp = Integer.parseInt("" + ch[++i]); while (i < ch.length - 1 && Character.isDigit(ch[++i])) { tmp = tmp * 10 + Integer.parseInt("" + ch[i]); } if (i != ch.length - 1) { i--; } stackOfNumber.push(tmp); int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); stackOfNumber.push(tmp1 * tmp2); stackOfTocken.pop(); } if (!(stackOfTocken.isEmpty()) && (char) stackOfTocken.peek() == ‘/‘) { int tmp = Integer.parseInt("" + ch[++i]); while (i < ch.length - 1 && Character.isDigit(ch[++i])) { tmp = tmp * 10 + Integer.parseInt("" + ch[i]); } if (i != ch.length - 1) { i--; } stackOfNumber.push(tmp); int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); stackOfNumber.push(tmp2 / tmp1); stackOfTocken.pop(); } } // 将栈中的数字和运算法逆置,便于计算 reverse(stackOfNumber); reverse(stackOfTocken); while (!(stackOfTocken.isEmpty())) { if ((char) stackOfTocken.peek() == ‘+‘) { int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); stackOfNumber.push(tmp1 + tmp2); } if ((char) stackOfTocken.peek() == ‘-‘) { int tmp1 = Integer.parseInt("" + stackOfNumber.pop()); int tmp2 = Integer.parseInt("" + stackOfNumber.pop()); stackOfNumber.push(tmp1 - tmp2); } stackOfTocken.pop(); } return Float.parseFloat("" + stackOfNumber.pop()); } private void reverse(MyStack s) { if (s.isEmpty()) { return; } // 如果s里面只有一个元素,就返回。具体实现是先pop出来一个,判断剩下的是不是空栈。 Object tmp1 = s.pop(); reverse(s); if (s.isEmpty()) { s.push(tmp1); return; } Object temp2 = s.pop(); reverse(s); s.push(tmp1); reverse(s); s.push(temp2); } }
以及测试用例:
public class InfixExprTest { @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testEvaluate() { // InfixExpr expr = new InfixExpr("300*20+12*5-20/4"); { InfixExpr expr = new InfixExpr("2+3*4+5"); Assert.assertEquals(19.0, expr.evaluate(), 0.001f); } { InfixExpr expr = new InfixExpr("3*20+12*5-40/2"); Assert.assertEquals(100.0, expr.evaluate(), 0.001f); } { InfixExpr expr = new InfixExpr("3*20/2"); Assert.assertEquals(30, expr.evaluate(), 0.001f); } { InfixExpr expr = new InfixExpr("20/2*3"); Assert.assertEquals(30, expr.evaluate(), 0.001f); } { InfixExpr expr = new InfixExpr("10-30+50"); Assert.assertEquals(30, expr.evaluate(), 0.001f); } } }
时间: 2024-12-19 12:34:48