c2java 第5篇 栈和中缀表达式的直接计算

来源:互联网 发布:将字符串转换为json 编辑:程序博客网 时间:2024/04/30 07:12

中缀表达式一般是先转换为后缀表达式,然后再计算的,其实我们可以边转换边计算。

/*Infix.java使用两个栈直接求解中缀表达式,一个栈保存运算符S,一个栈保存操作数D。例子:a+b*c  D:a,b S:+    D:a,b,c S:+,*    D:a,bc  S:+ <-- 每次取一个运算符,弹两个操作数    D:a+bc  S:a*b/c+d  D: a,b S:*   D: a*b S:/ <-- 清空优先级大于等于除号的运算符     D:a*b/c S:+      D:a*b/c+d S:a^b^c  D:a,b S:^    D:a,b,c S:^,^ <-- 清空栈优先级大于等于幂号扫描优先级的运算符    D:a,b^c S:^    D:a^b^c S:a*(b+c)  D:a  S:*(    D:a,b S:*(+  D:a,b,c S:*(+)      D:a,b+c S:* <-- 清空操作符直到(      D:a*(b+c) S:这几种情形,通过赋予运算符适当的优先级,可统一为:  清空栈优先级大于等于扫描优先级的运算符 (R0)这里只是为了说明栈的应用,因此简单假设操作数是一位数字,并且没有空格,如果扩展成BigDecimal应该不困难。中缀表达式的计算规则,从左到右扫描一遍,在扫描过程中:  R1 如果遇到数字,则压入操作数栈D;  R2 如果遇到操作符,则根据R0弹出S中的操作符;  R3 每弹出一个操作符,就弹出D中两个操作数,并把结果压入D。扫描结束时,可能S不为空,按规则R3。最终D中仅有的一个是结果,S 应该为空。author: ludi 2014.04*/import java.util.Stack;public class Infix{public static int eval(int a, int b, char op){  int ret = 0;switch(op){case '+': ret = a + b; break; case '-': ret = a - b; break;case '*': ret = a * b; break;case '/': ret = a / b; break;case '%': ret = a % b; break;case '^': {ret = 1;while(b-- > 0){ret *= a;}}break;default: System.out.println("error op " + op); break;} return ret;  }public static int evaluate(String infix){Stack<Integer> d = new Stack<Integer>();Stack<Symbol> s = new Stack<Symbol>();int i, a, b;char ch;Symbol op, op2;for(i = 0; i < infix.length(); ++i){ch = infix.charAt(i);if (Character.isDigit(ch)){d.push(ch - '0');}else {op = new Symbol(ch);while(!s.empty() && (s.peek().compareTo(op) >= 0)){op2 = s.pop();b = d.pop();a = d.pop();d.push(eval(a, b,op2.op));}if(ch == ')'){s.pop(); /*弹出'('*/}else s.push(op);}}while(!s.empty()){op2 = s.pop();b = d.pop();a = d.pop();d.push(eval(a, b, op2.op));}System.out.printf("%s = %d d.size %d s.size %d%n", infix, d.peek(), d.size(), s.size());return d.pop();}public static void main(String[] arg){evaluate("1+2*3");evaluate("2*(3+4)");evaluate("2*3/2+1");evaluate("2^3^2");evaluate("(2^3)^2");evaluate("(2^3)^2+2^3^2+2*3/2+1+2*(3+4)");evaluate("2^(2*(3+4))");}} class Symbol implements Comparable<Symbol>{      char op;       int inputPrec; /*正在被扫描的操作符的优先级*/      int stackPrec; /*栈优先级:值越小停留在栈中时间越长*/       public Symbol (char ch){         op = ch;          switch(op){            case '+':            case '-':inputPrec = stackPrec = 1;                break;            case '*':            case '%':            case '/':   inputPrec = 2;                     stackPrec = 2;                     break;            case '^':inputPrec = 4;                    stackPrec = 3; /*右结合的操作符扫描大于栈优先级*/                    break;            case '(':   inputPrec = 5;                     stackPrec = -1; /*最高的扫描优先级,最低的栈优先级*/                    break;            case ')':   inputPrec = 0;                    stackPrec = 0;                    break;         }      }      public int compareTo(Symbol item)      {         int result;         if (stackPrec < item.inputPrec)            result = -1;         else if (stackPrec == item.inputPrec)            result = 0;         else            result = 1;         return result;      }      public char getOp()      { return op; }}/*ludi@msys ~/java$ javac -encoding UTF-8 Infix.java  && java Infix1+2*3 = 7 d.size 1 s.size 02*(3+4) = 14 d.size 1 s.size 02*3/2+1 = 4 d.size 1 s.size 02^3^2 = 512 d.size 1 s.size 0(2^3)^2 = 64 d.size 1 s.size 0(2^3)^2+2^3^2+2*3/2+1+2*(3+4) = 594 d.size 1 s.size 02^(2*(3+4)) = 16384 d.size 1 s.size 0ludi@msys ~/java*/


 

这里面为了简明起见,没有做错误处理。

很好奇编译器是怎么计算常量表达式的,不知道是不是这样子呢。

 

附:

一些与栈有关的有意思的话题:

[1] 神奇的卡塔兰数Catalan  http://blog.csdn.net/nupt123456789/article/details/22735113

 

0 0
原创粉丝点击