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

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

import java.util.Collections;
import java.util.Stack;

public class Calculator {
private Stack<String> postfixStack = new Stack<String>();//后缀式栈
private Stack<Character> opStack = new Stack<Character>();//运算符栈
private int [] operatPriority = new int[] {0,3,2,1,-1,1,0,2};//运用运算符ASCII码-40做索引的运算符优先级
public static void main(String[] args) {
System.out.println(5+12*(3+5)/7.0);
Calculator cal = new Calculator();
String s = "5+12*(3+5)/7";
double result = cal.calculate(s);
System.out.println(result);
}

/**
* 按照给定的表达式计算
* @param expression 要计算的表达式例如:5+12*(3+5)/7
* @return
*/
public double calculate(String expression) {
Stack<String> resultStack = new Stack<String>();
prepare(expression);
Collections.reverse(postfixStack);//将后缀式栈反转
String firstValue ,secondValue,currentValue;//参与计算的第一个值,第二个值和算术运算符
while(!postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if(!isOperator(currentValue.charAt(0))) {//如果不是运算符则存入操作数栈中
resultStack.push(currentValue);
} else {//如果是运算符则从操作数栈中取两个值和该数值一起参与运算
secondValue = resultStack.pop();
firstValue = resultStack.pop();
String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
resultStack.push(tempResult);
}
}
return Double.valueOf(resultStack.pop());
}

/**
* 数据准备阶段将表达式转换成为后缀式栈
* @param expression
*/
private void prepare(String expression) {
opStack.push(',');//运算符放入栈底元素逗号,此符号优先级最低
char[] arr = expression.toCharArray();
int currentIndex = 0;//当前字符的位置
int count = 0;//上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
char currentOp ,peekOp;//当前操作符和栈顶操作符
for(int i=0;i<arr.length;i++) {
currentOp = arr[i];
if(isOperator(currentOp)) {//如果当前字符是运算符
if(count > 0) {
postfixStack.push(new String(arr,currentIndex,count));//取两个运算符之间的数字
}
peekOp = opStack.peek();
if(currentOp == ')') {//遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
while(opStack.peek() != '(') {
postfixStack.push(String.valueOf(opStack.pop()));
}
opStack.pop();
} else {
while(currentOp != '(' && peekOp != ',' && compare(currentOp,peekOp) ) {
postfixStack.push(String.valueOf(opStack.pop()));
peekOp = opStack.peek();
}
opStack.push(currentOp);
}
count = 0;
currentIndex = i+1;
} else {
count++;
}
}
if(count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {//最后一个字符不是括号或者其他运算符的则加入后缀式栈中
postfixStack.push(new String(arr,currentIndex,count));
}

while(opStack.peek() != ',') {
postfixStack.push(String.valueOf( opStack.pop()));//将操作符栈中的剩余的元素添加到后缀式栈中
}
}

/**
* 判断是否为算术符号
* @param c
* @return
*/
private boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' ||c == ')';
}

/**
* 利用ASCII码-40做下标去算术符号优先级
* @param cur
* @param peek
* @return
*/
public boolean compare(char cur,char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
boolean result = false;
if(operatPriority[(peek)-40] >= operatPriority[(cur) - 40]) {
result = true;
}
return result;
}

/**
* 按照给定的算术运算符做计算
* @param firstValue
* @param secondValue
* @param currentOp
* @return
*/
private String calculate(String firstValue,String secondValue,char currentOp) {
String result = "";
switch(currentOp) {
case '+':
result = String.valueOf(ArithHelper.add(firstValue, secondValue));
break;
case '-':
result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
break;
case '*':
result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
break;
case '/':
result = String.valueOf(ArithHelper.div(firstValue, secondValue));
break;
}
return result;
}
}

public class ArithHelper {

// 默认除法运算精度
private static final int DEF_DIV_SCALE = 16;

// 这个类不能实例化
private ArithHelper() {
}

/**
* 提供精确的加法运算。
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/

public static double add(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}

public static double add(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.add(b2).doubleValue();
}

/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/

public static double sub(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}

public static double sub(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.subtract(b2).doubleValue();
}

/**
* 提供精确的乘法运算。
*
* @param v1
* 被乘数
* @param v2
* 乘数
* @return 两个参数的积
*/

public static double mul(double v1, double v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}

public static double mul(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.multiply(b2).doubleValue();
}

/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
*
* @param v1
* 被除数
* @param v2
* 除数
* @return 两个参数的商
*/

public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}

public static double div(String v1, String v2) {
java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}

/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/

public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}

/**
* 提供精确的小数位四舍五入处理。
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/

public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}

public static double round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
java.math.BigDecimal b = new java.math.BigDecimal(v);
java.math.BigDecimal one = new java.math.BigDecimal("1");
return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
}
}

java实现算术表达式求值的更多相关文章

  1. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  2. [Java]算术表达式求值之三(中序表达式转二叉树方案 支持小数)

    Entry类 这个类对表达式的合法性进行了粗筛: package com.hy; import java.io.BufferedReader; import java.io.IOException; ...

  3. 【算法】E.W.Dijkstra算术表达式求值

    算术表达式求值 我们要学习的一个栈的用例同时也是展示泛型的应用的一个经典例子,就是用来计算算术表达式的值,例如 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) ) 如果将4乘以5,把3 ...

  4. Dijkstra的双栈算术表达式求值算法

    这次来复习一下Dijkstra的双栈算术表达式求值算法,其实这就是一个计算器的实现,但是这里用到了不一样的算法,同时复习了栈. 主体思想就是将每次输入的字符和数字分别存储在两个栈中.每遇到一个单次结束 ...

  5. OpenJudge计算概论-简单算术表达式求值

    /*===================================== 简单算术表达式求值 总时间限制: 1000ms 内存限制: 65536kB 描述 2位正整数的简单算术运算(只考虑整数运 ...

  6. page80-栈用例-算术表达式求值

    表达式由括号, 运算符和操作数(数字)组成.我们根据以下4中情况从左到右逐个将这些实体送入栈处理. (1)将操作数压入操作数栈: (2)将运算符压入运算符栈: (3)忽略左括号: (4)在遇到右括号时 ...

  7. 算法手记(2)Dijkstra双栈算术表达式求值算法

    这两天看到的内容是关于栈和队列,在栈的模块发现了Dijkstra双栈算术表达式求值算法,可以用来实现计算器类型的app. 编程语言系统一般都内置了对算术表达式的处理,但是他们是如何在内部实现的呢?为了 ...

  8. 栈的一个实例——Dijkstra的双栈算术表达式求值法

    Dijkstra的双栈算术表达式求值法,即是计算算术表达式的值,如表达式(1 + ( (2+3) * (4*5) ) ). 该方法是 使用两个栈分别存储算术表达式的运算符与操作数 忽略左括号 遇到右括 ...

  9. [Java]算术表达式求值之二(中序表达式转后序表达式方案,支持小数)

    Inlet类,入口类,这个类的主要用途是验证用户输入的算术表达式: package com.hy; import java.io.BufferedReader; import java.io.IOEx ...

随机推荐

  1. Qt5:Qt程序不在任务拦显示图标

    setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint); 回头再写

  2. JSP中EL表达式取值问题记录(已解决)

    ***************************2015-10-28 22:21************************* 问题描述如下: 在当前的jsp页面已经有了如下代码: < ...

  3. 用JAVA捕获屏幕、屏幕录像、播放

    http://blog.csdn.net/njchenyi/article/details/447554 用JAVA捕获屏幕.屏幕录像.播放 标签: javaexceptionimageimportn ...

  4. Java虚拟机中的内存分配

    java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途以及创建和销毁的时间. 栈:存放的是局部变量,包括:1.用来保存基本数据类型的值:2.保存类 ...

  5. Servlet实现文件上传(简单)(一)

     1..使用到的jar包,为apache的一个子项目  此commons-fileupload-1.2.2需要以下commons-io-2.0.1的支持   2.页面展示fileUpload.jsp ...

  6. set multiset 集合实现众数的统计

    众数问题 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 所谓众数,就是对于给定的含有N个元素的多重集合,每个元素在S中出现次数最多的成为该元素的重数, 多重集合S重 ...

  7. 如何在Eclipse中安装PDT插件来开发PHP

    之前查过很多PDT的安装方法,60%都是让人直接安装All-in-one的PHP eclipse版本,纯属让人无语,而有些给出的PDT安装链接无法正确下载插件,对此,给出了我安装过的PDT插件下载地址 ...

  8. FMDB事务的使用

    http://blog.csdn.net/qq_29892943/article/details/50541439 首先,说一下事务是什么,比如说我们有一个学生表和一个学生成绩表,而且一个学生对应一个 ...

  9. [无关IT]就这样在凌晨写一篇吧~

    由于新浪博客广告实在太嚣张,自己也都是转载,故决定搬家至此,一改只转不写的习惯T^T,争取记录一下自己的小成长~日后有时间把脑子里的小东西一点点写出来~(好可怕的说)... 好了,睡了!各位爷早睡~ ...

  10. LoadLibrary失败的原因(转)

    背影: 今天终于把公司的SDK 动态链接库转为Java 可调用的JNI 格式.DLL的编译环境是VS2010,使用Debug 输出时调用正常,而用Release 输出却调用失败.这可把哥搞惨了,开始以 ...