Java中的计算器算法

来源:互联网 发布:网络对时软件 编辑:程序博客网 时间:2024/05/16 23:40

最近,在数据结构课上学习到了后缀表达式。于是决定重写之前做过的计算器APP的算法。(检测表达式合法性的是另外的算法,这里暂时不提及)首先我简单地对比这两种算法:

一、中缀表达式。

1.同时在两边遍历表达式,储存最里层的括号的位置a,b,和括号的对数n

2.将表达式按括号的位置裁剪出一个子表达,substring(a+1, b)

3.遍历子表达式,就将从开始位置0到运算符位置k剪切下来就是一个操作数字符串substring(0, k)。转化为double类型后存入一个链表numList中,将运算符存在charList中。起始位置改为运算符的下一位继续,直到等于号的出现。

4.如下图所示,下面是两个LinkedList,先计算乘号和除号,将与运算符对应位置与前一个位置的数字进行运算。如下计算乘法,2*3=6将结果6写到原来2的位置上,此时3和乘号要从链表里面删去。经过两次遍历(先乘除后加减),最后numList只剩最终结果,charList只剩等于号。

 

5.将结果数字转换为字符串后取代原来在括号中的表达式。循环n+1次运算会得到最终结果。

二、后缀表达式。

1.遍历表达式,数字直接切下加到另外的StringBuilder里,而若为 '(',入栈;

2.若为 ')',则依次把栈中的的运算符加入后缀表达式中,直到出现'(',从栈中删除'(' 

3.若为除括号外的其他运算符, 当其优先级高于除'('以外的栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或者遇到了一个左括号为止。(构造方法中,定义了运算符的优先级)

public Caculate(String exp) {this.exp = exp;stBuilder = new StringBuilder();stack = new Stack<String>();map = new HashMap<String, Integer>();map.put("=", 0);map.put("+", 1);map.put("-", 1);map.put("×", 2);map.put("÷", 2);map.put("(", 3);map.put(")", 3);}


4.当扫描的中缀表达式结束时,栈中的的所有运算符出栈

(后缀表达式的转化完成,注意新的Sting里每个后面都加了空格方便后面的计算)

public String convertToRPN() {int start = 0;for (int i = 0; i < exp.length(); i++) {if (exp.charAt(i)=='='||exp.charAt(i)=='-'||exp.charAt(i)=='+'||exp.charAt(i)=='×'||exp.charAt(i)=='÷'||exp.charAt(i)=='('||exp.charAt(i)==')') {if (exp.charAt(start)>='0'&&exp.charAt(start)<='9') {stBuilder.append(exp.substring(start, i) + " ");}start = i + 1;putIntoStack(String.valueOf(exp.charAt(i)));}}if (!stack.empty()) {   stBuilder.append(stack.pop());}return stBuilder.toString();}
private void putIntoStack(String operation) {System.out.println(operation);while (!stack.empty()) {String top = stack.peek();//System.out.println("top " + top);if (operation.equals("(")) {stack.push(operation);break;} else if (operation.equals(")")) {while (!top.equals("(")) {stBuilder.append(top + " ");System.out.println("test1 " + stack.pop());top = stack.peek();System.out.println("test2 " + top);}stack.pop();break;} else if (top.equals("(")) {stack.push(operation);break;} else if(map.get(top) >= map.get(operation)) {stBuilder.append(top + " ");stack.pop();} else {stack.push(operation);break;}}if (stack.empty()) {stack.push(operation);}System.out.println(stack.toString());}

5.遍历后缀表达式,数字入栈,遇到运算符弹出两个数字计算再压入栈中,最后剩下来的就是运算结果。显然后缀表达式的方法思路更清晰。

public String caculate(String exp) {Stack<Double> stack = new Stack<Double>();for (String s : exp.split(" ")) {if (s.charAt(0) >= '0' && s.charAt(0) <= '9') {stack.push(Double.parseDouble(s));} else {                BigDecimal a, b, d;switch (s.charAt(0)) {case '+':a = BigDecimal.valueOf(stack.pop());b = BigDecimal.valueOf(stack.pop());d = a.add(b);stack.push(d.doubleValue());break;case '-':                    a = BigDecimal.valueOf(stack.pop());                    b = BigDecimal.valueOf(stack.pop());                    d = b.subtract(a);                    stack.push(d.doubleValue());break;case '×':                    a = BigDecimal.valueOf(stack.pop());                    b = BigDecimal.valueOf(stack.pop());                    d = a.multiply(b);                    stack.push(d.doubleValue());break;case '÷':                    a = BigDecimal.valueOf(stack.pop());                    b = BigDecimal.valueOf(stack.pop());                    d = b.divide(a, 16, BigDecimal.ROUND_HALF_DOWN);                    stack.push(d.doubleValue());break;}}}return String.valueOf(stack.pop());}
(因为java的基本数据类型的浮点型运算会有误差,在商业计算中使用BigDecimal类运算,BigDecimal类封装了误差纠正的方法。看这解释)

0 0