zoukankan      html  css  js  c++  java
  • java实现算术表达式求值

        需要根据配置的表达式(例如: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 }
  • 相关阅读:
    不同浏览器对于js中for循环的判断
    png格式图片背景不透明问题解决
    qq登陆错误提示
    T职场人生系列之二十四:程序员如何增加收入
    if [ $# eq 0 ]该语句是什么含义?
    动态IP修改注册表降低PING值教程(XP系统)
    c# List列表数据转换成树形结构
    net core EF 链接mysql 数据库
    net core 部署到windows 服务
    IdentityServer4 密码模式认证
  • 原文地址:https://www.cnblogs.com/gmq/p/3108849.html
Copyright © 2011-2022 走看看