java實現算術表達式求值


需要根據配置的表達式(例如: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();
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM