您的位置:首页 > 其它

简单字符串表达式的计算

2018-02-26 15:23 183 查看
最近看了后缀表达式,之前也遇到过类似的面试题,遂写这篇博客,用于以后复用(其中表达式的校验并没有完成)。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());
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法