简单字符串表达式的计算

最近看了后缀表达式,之前也遇到过类似的面试题,遂写这篇博客,用于以后复用(其中表达式的校验并没有完成)。

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

/**
 * 字符串表达式计算 
 *
 * 2018年2月26日上午11:18:08
 */
public class StringExpressEvaluateUtil {

	/**
	 * 符号优先级集合
	 * 该优先级别用于将中缀表达式转换成后缀表达式过程中使用
	 */
	final static Map<String,Integer> SIGNP_RIORITY =new HashMap<>(); 

	/**
	 * 成对符号集合
	 * 暂时仅用于在将中缀表达式转换成后缀表达式过程中,校验到")",往前匹配左括号。
	 */
	final static Map<String,Integer> SIGNP_PAIR =new HashMap<>();
	
	private StringExpressEvaluateUtil(){
		//不允许外部进行实例化
	}
	private static StringExpressEvaluateUtil instance;
	
	private static StringExpressEvaluateUtil getInstance(){
		if(instance == null) {
			return new StringExpressEvaluateUtil();
		}else {
			return instance;
		}
	}

	static {

		SIGNP_RIORITY.put("+", 1);
		SIGNP_RIORITY.put("-", 1);
		SIGNP_RIORITY.put("*", 2);
		SIGNP_RIORITY.put("/", 2);
		SIGNP_RIORITY.put("(", -1);
		
		SIGNP_PAIR.put("(",-1);
		SIGNP_PAIR.put(")", 1);
		
	}

	/**
	 * 
	 * @param srcExpress 原始表达式
	 * @return 后缀表达式,用于具体的计算使用
	 * @author riseSun
	
	 * 2018年2月26日上午11:19:59
	 */
	public String transformExpress(String srcExpress) {
		
		if(srcExpress == null) {
			throw new IllegalArgumentException("原始表达式不能为null");
		}

		StringBuilder postfixExpress = new StringBuilder();

		if("".equals(srcExpress.trim())) {
			return postfixExpress.toString();
		}

		//校验原始表达式是否有误
		checkSrcExpress(srcExpress);
		//符号栈 = 中缀->后缀中间产品
		Stack<String> signStack = new Stack<String>();

		/**
		 * 这里为了简单,所以假定原始表达式中,各个字符间具有空格,这样有助于表达式中数据的获取,如下表达式示例中,
		 * 要提取其中的数字30,以及10.2比较麻烦。
		 * 当然,如果没有空格,本人想到使用一下方法:
		 * {假设表达式为:-9+(30-1)*3+10.2/2 }
		 *	将其中的数字,用a、b、c、d、e...代替(记录代替的数字) ,这样可以使用toCharArray()或者split("");获取其中的字符。
		 *  获取到最终后缀表达式之后,将这些字母用原先的数字替换(这个替换过程可以在具体计算表达式的时候再做)
		 */
		for(String c: srcExpress.split(" ")) {
			switch (c) {
				case "+":
				case "-":
				case "*":
				case "/":
					operateSign(c,signStack,postfixExpress);
					break;
				case "(":
					//左括号直接压入到符号栈中
					signStack.push(c);
					break;
				case ")":
					//右括号单独处理
					operateParentheses(c,signStack,postfixExpress);
					break;
				default:
					//除符号外,其他的操作数直接追加到输出中
					postfixExpress.append(" "+c);
					break;
			}
		}
		//最后将符号栈中剩余的符号,追加到输出中
		while(!signStack.isEmpty()) {
			postfixExpress.append(" "+signStack.pop());
		}
		return postfixExpress.toString();
	}
	/**
	 * 校验字符串表达式的正确性
	 * @param srcExpress
	 * @author riseSun
	
	 * 2018年2月26日下午2:55:26
	 */
	public void checkSrcExpress(String srcExpress) {
//		if(false) {
//			throw new IllegalArgumentException("原始表达式存在错误");
//		}
	}
	/**
	 * 处理读取的符号
	 * @param newSign
	 * @param signStack
	 * @param postfixStack
	 * @author riseSun
	
	 * 2018年2月26日下午12:46:38
	 */
	public void operateSign(String newSign,Stack<String> signStack,StringBuilder postfixExpress) {
		//满足空栈或者优先级大于符号栈顶元素的优先级时,将符号直接压入栈中
		if(signStack.isEmpty() || (SIGNP_RIORITY.get(newSign) > SIGNP_RIORITY.get(signStack.peek()))) {
			signStack.push(newSign);
		}else {//出栈,直到栈顶元素优先级<=新符号,或者空栈
			//将符号打印到后缀栈中
			postfixExpress.append(" "+signStack.pop());
			operateSign(newSign, signStack, postfixExpress);
		}
	}
	/**
	 * 处理右括号
	 * 从符号栈中压出元素,并将元素压入到结果栈中,
	 * 直到符号栈中压出相反的符号为止
	 * @param newSign
	 * @param signStack
	 * @param postfixStack
	 * @author riseSun
	 * 2018年2月26日下午12:47:16
	 */
	public void operateParentheses(String newSign,Stack<String> signStack,StringBuilder postfixExpress) {
		while(!signStack.isEmpty() && !isPair(newSign,signStack.peek())) {
			postfixExpress.append(" "+signStack.pop());
		}
		//废弃栈中的左括号
		signStack.pop();
	}
	/**
	 * 判断两个符号是否是对称符号,例如(),[],{}..等
	 * 由SIGNP_PAIR来维护对称关系
	 * @param sign
	 * @param anotherSign
	 * @author riseSun
	
	 * 2018年2月26日下午12:53:30
	 */
	public boolean isPair(String sign,String anotherSign) {
		Integer signInt;
		Integer anotherSignInt;
		return (signInt = SIGNP_PAIR.get(sign)) !=null 
				&& (anotherSignInt = SIGNP_PAIR.get(anotherSign)) !=null 
				&& signInt.intValue()+anotherSignInt.intValue() == 0;
	}

	
	/**
	 * 根据后缀表达式进行计算
	 * @param postfixStack
	 * @return
	 * @author riseSun
	
	 * 2018年2月26日下午2:20:05
	 */
	public static double evaluate(String postfixStack) {

		//用于存放操作数以及中间计算结果
		Stack<String> evaluteStack = new Stack<>();

		String[] source = postfixStack.split(" ");

		for(String s : source) {
			double result;
			switch(s) {
				case "+":
					result = Double.parseDouble(evaluteStack.pop()) + Double.parseDouble(evaluteStack.pop());
					evaluteStack.push(result+"");
					break;
				case "-":
					double meiosis = Double.parseDouble(evaluteStack.pop());//减数
					double minuend = Double.parseDouble(evaluteStack.pop());//被减数
					result = minuend - meiosis;
					evaluteStack.push(result+"");
					break;
				case "*":
					result = Double.parseDouble(evaluteStack.pop()) * Double.parseDouble(evaluteStack.pop());
					evaluteStack.push(result+"");
					break;
				case "/":
					double divisor = Double.parseDouble(evaluteStack.pop());//除数
					double dividend = Double.parseDouble(evaluteStack.pop());//被除数
					result = dividend / divisor; 
					evaluteStack.push(result+"");
					break;
				default:
					//操作数直接压入栈中
					evaluteStack.push(s);
					break;
			}
		}
		//返回最终留在栈中的结果
		return Double.parseDouble(evaluteStack.pop());
	}

	/**
	 * 根据中缀表达式,直接计算结果
	 * @param midExpress
	 * @return
	 * @author riseSun
	
	 * 2018年2月26日下午3:02:28
	 */
	public static double evaluateMidExpress(String midExpress) {
		StringExpressEvaluateUtil instance = getInstance();
		return StringExpressEvaluateUtil.evaluate(instance.transformExpress(midExpress).trim());
	}
	
}

猜你喜欢

转载自blog.csdn.net/jianlong1284537512/article/details/79377620