1. 程式人生 > >使用Java求數學表示式的值

使用Java求數學表示式的值

關於怎麼求數學表示式的值,網上有很多教程。但大多教程只是一個Demo,該Demo只實現了個位數的四則運算,遇到個位數以上的計算時就會出現問題。本文在此基礎上進行了擴充套件,實現了個位數以上的四則運算。

整體思路:

輸入的表示式為中綴表示式,將該表示式轉為後序表示式然後利用棧做運算。

中綴表示式轉字尾表示式的方法:(用list存放字尾表示式中各元素,用棧stack臨時存放運算子)

1:遇到數字時:將其放入list。

2:遇到運算子時:當運算子時乘號或者除號時直接入棧。當運算子時加減號時:若棧為空則直接入棧;否則,獲取棧頂運算子topOper(是獲取,而不是彈出,故用peek而不是pop),若topOper為左括號時,直接入棧,否則迴圈獲取棧中左括號上面的元素加入list,最後將當前運算子入棧。

3:遇到左括號(“(”)時,直接入棧;

4:遇到右括號時(“)”),依次出棧,當出棧運算子為左括號時,退出。

5:最終將棧中的各元素依次出棧放入list。

使用字尾表示式求值的方法:

依次遍歷list中的各元素進行入棧,當得到的元素為運算子時,取出棧頂的兩個元素做運算,然後將運算結果入棧,直到list遍歷完成。

程式碼如下:

import java.util.*;

public class MyStackCalculators {

	public static void main(String[] args) {

		String string = "(7+4*3+10*(3-3+4-1-8-10))";
		List<String> inputList = strToList(string);
		List<String> postfix = getPostfixExpression(inputList);
		String res = getRes(postfix);
		System.out.println("最終結果為:" + res);
	}
	
	/**
	 * 獲取輸入表示式中的各元素,並用list進行儲存。
	 * @param expression
	 * @return
	 */
	private static List<String> strToList(String expression) {

		List<String> arrayList = new ArrayList<String>();
		char ch[] = expression.toCharArray();
		String v = "";
		for(int i=0; i<ch.length; i++) {
			char e = ch[i];
			if(e >= '0' && e <= '9') {
				v += e;
			} else {
				if(v != "") {
					arrayList.add(v);
				}
				arrayList.add(e + "");
				v = "";
			}
		}
		if(v != "") {
			arrayList.add(v);
		}
		return arrayList;
	}
	
	private static List<String> getPostfixExpression(List<String> list) {

		List<String> pfixExpList = new ArrayList<>();//存放字尾表示式中各元素的list
		Stack<String> stack = new Stack<>();//存放運算子的棧
		for(int i=0; i<list.size(); i++) {
			String tm = list.get(i);
			if(tm.matches("[0-9]*")) {//當得到的元素是數字時,直接放入list。
				pfixExpList.add(tm);
			} else if(tm.equals("(")) {//當得到元素是左括號時,直接入棧
				stack.push(tm);
			} else if(tm.equals(")")){//當得到元素是右括號時
				//執行出棧操作,並將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出。
				String s = stack.pop();
				while(!(s.equals("(")) && !stack.isEmpty()) {
					pfixExpList.add(s);
					s = stack.pop();//此語句最終會彈出左括號
				}
			} else { //是運算子
				if(tm.equals("*") || tm.equals("/")) { //乘號和除號情況,直接入棧
					stack.push(tm);
				} else {//加減號情況,取出棧中的“(”上面的全部元素存入list1,最後將當前運算子入棧
					if(stack.isEmpty()) {
						stack.push(tm);
					} else {
						String s = stack.peek();
						if(s.equals("(")) {
							stack.push(tm);
						} else {
							while(!s.equals("(") && !stack.isEmpty()) {
								pfixExpList.add(stack.pop());
								s = stack.peek();
							}
							stack.push(tm);//將當前運算子入棧
						}
					}
				}
			}
		}
		//將棧中剩餘元素存入list
		while(!stack.isEmpty()) {
			pfixExpList.add(stack.pop());
		}
		return pfixExpList;
	}

	/**
	 * 得到表示式的最終值
	 * @param list 存放的字尾表示式各元素
	 * @return
	 */
	private static String getRes(List<String> list) {

		Stack<String> stack = new Stack<String>();//存放結果用
		for(int i=0; i<list.size(); i++) {
			String el = list.get(i);
			if(el.matches("[0-9]*")) {//若為數字,直接入棧。
				stack.push(el);
			} else {//若不為數字,則取出棧頂的兩個元素做運算,並將結果入棧
				int v1 = 0;
				int v2 = 0;
				int res = 0;
				switch(el) {
				case "+":
					v2 = Integer.valueOf(stack.pop());
					v1 = Integer.valueOf(stack.pop());
					res = (v1 + v2);
					stack.push(res+"");
					break;
				case "-":
					v2 = Integer.valueOf(stack.pop());
					v1 = Integer.valueOf(stack.pop());
					res = (v1 - v2);
					stack.push(res+"");
					break;
				case "*":
					v2 = Integer.valueOf(stack.pop());
					v1 = Integer.valueOf(stack.pop());
					res = (v1 * v2);
					stack.push(res+"");
					break;
				case "/":
					v2 = Integer.valueOf(stack.pop());
					v1 = Integer.valueOf(stack.pop());
					res = (v1 / v2);
					stack.push(res+"");
					break;
				}
			}
		}
		return stack.pop();
	}
}

執行結果如下:

最終結果為:-131

注:關於這程式碼還有一個問題就是當表示式中有乘和除連續的時候,是按照其出現的順序計算的,這會導致1/3*3為0的情況。