no pain no gain

hard working

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

    需要根据配置的表达式(例如:5+12*(3+5)/7.0)计算出相应的结果,因此使用java中的栈利用后缀表达式的方式实现该工具类。

    后缀表达式就是将操作符放在操作数的后面展示的方式,例如:3+2 后缀表达式为32+,3*(2+1)的后缀表达式为:321+*,解决表达式求值首先需要根据字符串表达式求出后缀表达式,然后使用后缀表达式和操作数栈实现计算,计算的大致思想是从后缀表达式中取元素,如果元素是数值则加入到操作数栈中,如果是运算符则从操作数栈中取两个数来参与运算。后缀表达式的获取要借助于两个栈,一个是后缀表达式栈,一个是操作符栈,顺序扫描算术表达式,如果是数值则直接加入后缀表达式栈,如果是运算符则使用当前运算符和运算符栈中的栈顶元素做比较,如果当前运算符的优先级高则当前元素进入操作符栈,如果当前元素优先级低,则操作符栈顶元素出栈加入到后缀表达式栈中,一直到当前元素优先级高于操作符栈顶元素优先级则当前元素入操作符栈,目前只支持加减乘除和带小括号的运算。

  1 import java.util.Collections;
  2 import java.util.Stack;
  3 
  4 public class Calculator {
  5     private Stack<String> postfixStack  = new Stack<String>();//后缀式栈
  6     private Stack<Character> opStack  = new Stack<Character>();//运算符栈
  7     private int [] operatPriority  = new int[] {0,3,2,1,-1,1,0,2};//运用运算符ASCII码-40做索引的运算符优先级
  8     public static void main(String[] args) {
  9         System.out.println(5+12*(3+5)/7.0);
 10         Calculator cal  = new Calculator();
 11         String s = "5+12*(3+5)/7";
 12         double result  = cal.calculate(s);
 13         System.out.println(result);
 14     }
 15 
 16     /**
 17      * 按照给定的表达式计算
 18      * @param expression 要计算的表达式例如:5+12*(3+5)/7
 19      * @return
 20      */
 21     public double calculate(String expression) {
 22         Stack<String> resultStack  = new Stack<String>();
 23         prepare(expression);
 24         Collections.reverse(postfixStack);//将后缀式栈反转
 25         String firstValue  ,secondValue,currentValue;//参与计算的第一个值,第二个值和算术运算符
 26         while(!postfixStack.isEmpty()) {
 27             currentValue  = postfixStack.pop();
 28             if(!isOperator(currentValue.charAt(0))) {//如果不是运算符则存入操作数栈中
 29                 resultStack.push(currentValue);
 30             } else {//如果是运算符则从操作数栈中取两个值和该数值一起参与运算
 31                  secondValue  = resultStack.pop();
 32                  firstValue  = resultStack.pop();
 33                  String tempResult  = calculate(firstValue, secondValue, currentValue.charAt(0));
 34                  resultStack.push(tempResult);
 35             }
 36         }
 37         return Double.valueOf(resultStack.pop());
 38     }
 39     
 40     /**
 41      * 数据准备阶段将表达式转换成为后缀式栈
 42      * @param expression
 43      */
 44     private void prepare(String expression) {
 45         opStack.push(',');//运算符放入栈底元素逗号,此符号优先级最低
 46         char[] arr  = expression.toCharArray();
 47         int currentIndex  = 0;//当前字符的位置
 48         int count = 0;//上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
 49         char currentOp  ,peekOp;//当前操作符和栈顶操作符
 50         for(int i=0;i<arr.length;i++) {
 51             currentOp = arr[i];
 52             if(isOperator(currentOp)) {//如果当前字符是运算符
 53                 if(count > 0) {
 54                     postfixStack.push(new String(arr,currentIndex,count));//取两个运算符之间的数字
 55                 }
 56                 peekOp = opStack.peek();
 57                 if(currentOp == ')') {//遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
 58                     while(opStack.peek() != '(') {
 59                         postfixStack.push(String.valueOf(opStack.pop()));
 60                     }
 61                     opStack.pop();
 62                 } else {
 63                     while(currentOp != '(' && peekOp != ',' && compare(currentOp,peekOp) ) {
 64                         postfixStack.push(String.valueOf(opStack.pop()));
 65                         peekOp = opStack.peek();
 66                     }
 67                     opStack.push(currentOp);
 68                 }
 69                 count = 0;
 70                 currentIndex = i+1;
 71             } else {
 72                 count++;
 73             }
 74         }
 75         if(count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {//最后一个字符不是括号或者其他运算符的则加入后缀式栈中
 76             postfixStack.push(new String(arr,currentIndex,count));
 77         } 
 78         
 79         while(opStack.peek() != ',') {
 80             postfixStack.push(String.valueOf( opStack.pop()));//将操作符栈中的剩余的元素添加到后缀式栈中
 81         }
 82     }
 83     
 84     /**
 85      * 判断是否为算术符号
 86      * @param c
 87      * @return
 88      */
 89     private boolean isOperator(char c) {
 90         return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' ||c == ')';
 91     }
 92     
 93     /**
 94      * 利用ASCII码-40做下标去算术符号优先级
 95      * @param cur
 96      * @param peek
 97      * @return
 98      */
 99     public  boolean compare(char cur,char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
100         boolean result  = false;
101         if(operatPriority[(peek)-40] >= operatPriority[(cur) - 40]) {
102            result = true;
103         }
104         return result;
105     }
106     
107     /**
108      * 按照给定的算术运算符做计算
109      * @param firstValue
110      * @param secondValue
111      * @param currentOp
112      * @return
113      */
114     private String calculate(String firstValue,String secondValue,char currentOp) {
115         String result  = "";
116         switch(currentOp) {
117             case '+':
118                 result = String.valueOf(ArithHelper.add(firstValue, secondValue));
119                 break;
120             case '-':
121                 result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
122                 break;
123             case '*':
124                 result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
125                 break;
126             case '/':
127                 result = String.valueOf(ArithHelper.div(firstValue, secondValue));
128                 break;
129         }
130         return result;
131     }
132 }
  1 public class ArithHelper {
  2 
  3     // 默认除法运算精度
  4     private static final int DEF_DIV_SCALE = 16;
  5 
  6     // 这个类不能实例化
  7     private ArithHelper() {
  8     }
  9 
 10     /**
 11      * 提供精确的加法运算。
 12      * 
 13      * @param v1 被加数
 14      * @param v2 加数
 15      * @return 两个参数的和
 16      */
 17 
 18     public static double add(double v1, double v2) {
 19         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
 20         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
 21         return b1.add(b2).doubleValue();
 22     }
 23     
 24     public static double add(String v1, String v2) {
 25         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
 26         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
 27         return b1.add(b2).doubleValue();
 28     }
 29 
 30     /**
 31      * 提供精确的减法运算。
 32      * 
 33      * @param v1 被减数
 34      * @param v2 减数
 35      * @return 两个参数的差
 36      */
 37 
 38     public static double sub(double v1, double v2) {
 39         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
 40         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
 41         return b1.subtract(b2).doubleValue();
 42     }
 43     
 44     public static double sub(String v1, String v2) {
 45         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
 46         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
 47         return b1.subtract(b2).doubleValue();
 48     }
 49 
 50     /**
 51      * 提供精确的乘法运算。
 52      * 
 53      * @param v1
 54      *            被乘数
 55      * @param v2
 56      *            乘数
 57      * @return 两个参数的积
 58      */
 59 
 60     public static double mul(double v1, double v2) {
 61         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
 62         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
 63         return b1.multiply(b2).doubleValue();
 64     }
 65     
 66     public static double mul(String v1, String v2) {
 67         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
 68         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
 69         return b1.multiply(b2).doubleValue();
 70     }
 71 
 72     /**
 73      * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
 74      * 
 75      * @param v1
 76      *            被除数
 77      * @param v2
 78      *            除数
 79      * @return 两个参数的商
 80      */
 81 
 82     public static double div(double v1, double v2) {
 83         return div(v1, v2, DEF_DIV_SCALE);
 84     }
 85     
 86     public static double div(String v1, String v2) {
 87         java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
 88         java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
 89         return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
 90     }
 91 
 92     /**
 93      * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
 94      * 
 95      * @param v1 被除数
 96      * @param v2 除数
 97      * @param scale 表示表示需要精确到小数点以后几位。
 98      * @return 两个参数的商
 99      */
100 
101     public static double div(double v1, double v2, int scale) {
102         if (scale < 0) {
103             throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
104         }
105         java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
106         java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
107         return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
108     }
109 
110     /**
111      * 提供精确的小数位四舍五入处理。
112      * 
113      * @param v 需要四舍五入的数字
114      * @param scale 小数点后保留几位
115      * @return 四舍五入后的结果
116      */
117 
118     public static double round(double v, int scale) {
119         if (scale < 0) {
120             throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
121         }
122         java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
123         java.math.BigDecimal one = new java.math.BigDecimal("1");
124         return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
125     }
126     
127     public static double round(String v, int scale) {
128         if (scale < 0) {
129             throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
130         }
131         java.math.BigDecimal b = new java.math.BigDecimal(v);
132         java.math.BigDecimal one = new java.math.BigDecimal("1");
133         return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
134     }
135 }

 

posted on 2013-05-30 19:19  龚明秋  阅读(27954)  评论(4编辑  收藏  举报