【java】通过栈计算标准四则表达式

如何处理数学表达式(一般是字符串型的),如:(1+2*3/4+5+(6*7)/8)。

处理思路:

1、将表达式转换为后缀表达式(也称为逆波兰表达式);

2、计算后缀表达式。

想了解后缀表达式,请参考百度百科:后缀表达式百度百科

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class StackDemo {

	private static Map<String, Character> OPER_CHAR_MAP = null;
	
	public static double calMathExpression(String expression) throws Exception {
		expression = expression.trim().replaceAll(" ", "");
		System.out.println(convertToRPN(expression));
		return calRPN(convertToRPN(expression));
	}

	/**
	 * 初始化四则运算符map +、-、*(×)、/(÷) ()
	 */
	private static void initOperCharMap() {
		if (OPER_CHAR_MAP == null || OPER_CHAR_MAP.isEmpty()) {
			OPER_CHAR_MAP = new HashMap<>();
			Character additon = new Character("+", 0);
			Character subtraction = new Character("-", 0);
			Character multiplication = new Character("*", 1);
			Character division = new Character("/", 1);
			Character left_bracket = new Character("(", 2);
			Character right_bracket = new Character(")", 2);
			OPER_CHAR_MAP.put("+", additon);
			OPER_CHAR_MAP.put("-", subtraction);
			OPER_CHAR_MAP.put("×", multiplication);
			OPER_CHAR_MAP.put("*", multiplication);
			OPER_CHAR_MAP.put("÷", division);
			OPER_CHAR_MAP.put("/", division);
			OPER_CHAR_MAP.put("(", left_bracket);
			OPER_CHAR_MAP.put(")", right_bracket);
			additon = null;
			subtraction = null;
			multiplication = null;
			division = null;
			left_bracket = null;
			right_bracket = null;
		}
	}

	/**
	 * 把标准四则表达式转为后缀表达式,以" "分隔每个数字
	 */
	private static String convertToRPN(String expression) throws Exception {
		StringBuffer rpn_expression = new StringBuffer();
		Stack<Character> char_stack = new Stack<>();
		// 表达式按照每个字符拆分,考虑多位数,因此在遇到运算符前,用temp累计
		StringBuffer temp = new StringBuffer();
		// "(" 出现的次数
		int left_bracket_cnt = 0;
		for (int i = 0; i < expression.length(); i++) {
			String s = expression.substring(i, i + 1);
			if (isOperationalCharacter(s) != null || i == expression.length() - 1) {
				try {
					// 输出temp中的数字
					if (temp.length() > 0) {
						double num = Double.parseDouble(temp.toString());
						rpn_expression.append(num);
						// 分隔符
						rpn_expression.append(" ");
						// 初始化temp
						temp = new StringBuffer();
					}
					// 输出运算符
					Character c = OPER_CHAR_MAP.get(s);
					if (char_stack.isEmpty()) {
						char_stack.push(c);
					} else {
						switch (c.getValue()) {
						case "(":
							// "("直接入栈,等匹配后面的"("
							char_stack.push(c);
							left_bracket_cnt++;
							break;
						case "*":
						case "/":
						case "+":
						case "-":
							// 如果当前的运算不优先于栈顶的,则出栈。"( )"除外
							while (!char_stack.isEmpty() && !c.isPrioritizeThen(char_stack.peek())
									&& !char_stack.peek().value.equals("(")) {
								rpn_expression.append(char_stack.pop().value);
								rpn_expression.append(" ");
							}
							// 当前运算符入栈
							char_stack.push(c);
							break;
						case ")":
							// 依次输出"("前所有的运算符
							if (left_bracket_cnt != 0) {
								while (!char_stack.peek().value.equals("(")) {
									rpn_expression.append(char_stack.pop().value);
									rpn_expression.append(" ");
								}
								// 移除栈顶的"("
								char_stack.pop();
							}
							break;
						default:
							break;
						}
					}
				} catch (NumberFormatException e) {
					throw new NumberFormatException("不支持的运算符或数字");
				} catch (Exception e) {
					throw new Exception("表达式格式不正确");
				}
			} else {
				temp.append(s);
			}
		}
		return rpn_expression.toString();
	}

	/**
	 * 判断字符串是否为标准四则运算符 +、-、*(×)、/(÷)
	 * 
	 * @param str
	 * @return
	 */
	private static String isOperationalCharacter(String str) {
		initOperCharMap();
		str = str.trim();
		if (OPER_CHAR_MAP.containsKey(str)) {
			return str;
		} else {
			return null;
		}
	}

	/**
	 * 计算后缀表达式
	 * 
	 * @return
	 */

	private static double calRPN(String rpn_expression) {
		String[] characters = rpn_expression.split(" ");
		Stack<Double> char_stack = new Stack<>();
		for (int i = 0; i < characters.length; i++) {
			if (isOperationalCharacter(characters[i]) == null) {
				char_stack.push(Double.parseDouble(characters[i]));
			} else {
				double first = char_stack.pop();
				double second = char_stack.pop();
				switch (characters[i]) {
				case "*":
					char_stack.push(first * second);
					break;
				case "/":
					char_stack.push(second / first);
					break;
				case "+":
					char_stack.push(first + second);
					break;
				case "-":
					char_stack.push(second - first);
					break;
				default:
					break;
				}
			}
		}
		return char_stack.pop();
	}

	/**
	 * 四则运算符
	 * 
	 * @author kevingcang
	 *
	 */
	static class Character {
		/**
		 * 值
		 */
		private String value;
		/**
		 * 优先级
		 */
		private int priority;

		public Character(String value, int priority) {
			super();
			this.value = value;
			this.priority = priority;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}

		public int getPriority() {
			return priority;
		}

		public void setPriority(int priority) {
			this.priority = priority;
		}

		public boolean isPrioritizeThen(Character chr) {
			if (this.priority > chr.priority) {
				return true;
			} else {
				return false;
			}
		}
	}
	
	public static void main(String[] args) {
		String str = "(1+2*3/4+5+(6*7)/8)";
		try {
			System.out.println(StackDemo2.calMathExpression(str));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

四则表达式转后缀表达式、后缀表达式的计算主要借助栈来实现。原表达式为:(1+2*3/4+5+(6*7)/8) 转换为后缀表达式后 1 2 3 * 4 / + 5 + 6 7 * 8 / + 计算结果为:12.75。为方便数据用的double类型。


猜你喜欢

转载自blog.csdn.net/kevincang/article/details/80598047