package com.coding.basic.stack.expr;
import java.util.ArrayList;
import com.coding.basic.stack.Stack;
import com.coding.basic.stack.StackUtil;
public class InfixExpr {
private String expr = null;
public InfixExpr(String expr) {
this.expr = expr;
}
/**
* 对expr进行解析计算
* @return
*/
public float evaluate() {
float f = 0.0f;
//如果不为空继续解析
if (expr != null || expr.length() > 0) {
//如果符号不对称,抛出异常
if (!StackUtil.isValidPairs(expr)) {
try {
throw new Exception("格式不正确,解析表达式失败!");
} catch (Exception e) {
e.printStackTrace();
}
};
//将字符串转化为集合
ArrayList<String> list=getStringList(expr);
//根据获得的集合转化为后序表达式集合
ArrayList<String> postOrder = getPostOrder(list);
Stack stack = new Stack();
for (int i = 0; i < postOrder.size(); i++) {
//如果为数字,则压入栈
if(Character.isDigit(postOrder.get(i).charAt(0))){
stack.push(Float.parseFloat(postOrder.get(i)));
}else{
//否则,取出栈顶两个元素进行计算.
Float back = (Float)stack.pop();
Float front = (Float)stack.pop();
Float res = 0.0f;
switch (postOrder.get(i).charAt(0)) {
case '+':
res = front + back;
break;
case '-':
res = front - back;
break;
case '*':
res = front * back;
break;
case '/':
res = front / back;
break;
}
//将结果再压回栈中
stack.push(res);
}
}
//最终计算结果出栈;
f = (Float)stack.pop();
} else {
//为空抛出异常
try {
throw new Exception("表达式内容为空,解析失败!");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return f;
}
/**
* 将字符串转换为集合方法
* @param str
* @return
*/
private ArrayList<String> getStringList(String str) {
ArrayList<String> result = new ArrayList<String>();
String num = "";
for (int i = 0; i < str.length(); i++) {
//如果为数字,叠加到num字符串中
if (Character.isDigit(str.charAt(i))) {
num = num + str.charAt(i);
} else {
//如果num不为空,表示数字字符凑够了,加到集合里
if (num != "") {
result.add(num);
}
//然后再把非数字字符也加到集合中,清空num字符串
result.add(str.charAt(i) + "");
num = "";
}
}
//最后判断下,num中还有值没,有的话加到集合里
if (num != "") {
result.add(num);
}
//返回结果
return result;
}
/**
* 中序表达式转后序表达式
* @param list
* @return
*/
private ArrayList<String> getPostOrder(ArrayList<String> list) {
ArrayList<String> result = new ArrayList<String>();
Stack stack = new Stack();
for (int i = 0; i < list.size(); i++) {
//如果为数字,加到集合里
if (Character.isDigit(list.get(i).charAt(0))) {
result.add(list.get(i));
} else {
switch (list.get(i).charAt(0)) {
//如果有左括号,先压入操作符栈中
case '(':
stack.push(list.get(i));
break;
//ok,等到右括号了
case ')':
//先看看操作符栈顶是不是左括号头头
while (!stack.peek().equals("(")) {
//不是左括号头头,就把操作符栈中的操作符弹出来一个,加到集合里,一直弹到见到左括号为止
result.add((String) stack.pop());
}
//最后把左括号也弹出来,这样就只有加减乘除没有括号了
stack.pop();
break;
default:
//这里全是处理加减乘除的操作
//如果操作符栈不为空,比较下当前操作符和操作符栈顶的操作符优先级大小
while (!stack.isEmpty() && compare((String) stack.peek(), list.get(i))) {
//如果栈顶操作符优先级大于当前,则栈中的操作符弹出加到集合里
result.add((String) stack.pop());
}
//否则继续压到栈中,或者之前栈中元素已经弹出,再将优先级小的操作符加到操作符栈中.
stack.push(list.get(i));
break;
}
}
}
while (!stack.isEmpty()) {
//最后看下操作符栈还有操作符没,有了加到集合末尾
result.add((String) stack.pop());
}
return result;
}
/**
* 操作符优先级比较算法
* @param peek
* @param cur
* @return
*/
public static boolean compare(String peek, String cur) {
//乘除优先级大于加减
//如果操作符栈顶操作符的优先级大于当前操作符的优先级,则返回true
if ("*".equals(peek) && ("/".equals(cur) || "*".equals(cur) || "+".equals(cur) || "-".equals(cur))) {
return true;
} else if ("/".equals(peek) && ("/".equals(cur) || "*".equals(cur) || "+".equals(cur) || "-".equals(cur))) {
return true;
} else if ("+".equals(peek) && ("+".equals(cur) || "-".equals(cur))) {
return true;
} else if ("-".equals(peek) && ("+".equals(cur) || "-".equals(cur))) {
return true;
}
//如果当前操作符的优先级大于栈顶的操作符优先级,返回false
return false;
}
public static void main(String[] args) {
InfixExpr expr = new InfixExpr("3*20+13*5-40/2");
float f = expr.evaluate();
System.out.println(f);
}
}