通过学习java中的Stack栈,写一个一个简单的中缀表达式转换为后缀表达式并计算的应用
由于时间问题,没有写字符分割函数。暂时用空格进行分割
import java.util.Iterator;
import java.util.Stack;
public class Suffix2Infix {
public static void main(String[] args) {
// 创建对象
OperaExpression oe = new OperaExpression();
// 要计算得公式
// 没有去写辨别多位数的字符串方法,于是目前使用空格进行区分符号与数字
String ex = "9 + ( 3 - 1 * 3 ) * 3 + 10 / 2";
// 输出结果
System.out.println("结果:" + oe.getResult(ex));
}
}
class OperaExpression {
// 后缀表达式栈
public Stack<String> exp = new Stack<String>();
// 符号栈
public Stack<String> sym = new Stack<String>();
/**
* 返回结果方法
* @param ex 中缀表达式
* @return 结果
*/
public double getResult(String ex) {
// 中缀表达式转换为后缀表达式
System.out.println("中缀表达式:" + ex.replaceAll(" ", ""));
String ae = getAfterExpress(ex);
System.out.println("后缀表达式:" + ae);
// 计算结果
double result = operaBackExpress();
return result;
}
/**
* 计算后缀表达式方法
* @return 表达式运算结果
*/
private double operaBackExpress() {
// 创建结果栈
Stack<Double> result = new Stack<Double>();
// 遍历后缀表达式栈
for (Iterator iterator = exp.iterator(); iterator.hasNext();) {
// 得到栈内元素
String string = (String) iterator.next();
// 数字则存入结果栈
if (getType(string) == 1) {
result.push(Double.parseDouble(string));
}
// 如果非数字则进行计算
else {
// 取出结果栈内要计算的值
double a2 = result.pop();
double a1 = result.pop();
// 对值进行计算
double res = opera(a1, a2, string);
// 讲结果存入结果栈
result.push(res);
}
}
// 取出结果栈内最终得结果
return result.pop();
}
/**
* 运算方法
* @param a1 第一个值
* @param a2 第二个值
* @param string 符号
* @return 计算结果
*/
private double opera(double a1, double a2, String string) {
switch (string) {
case "+":
return a1 + a2;
case "-":
return a1 - a2;
case "*":
return a1 * a2;
case "/":
return a1 / a2;
default:
throw new RuntimeException(string + "运算错误");
}
}
/**
* 中缀表达式转后缀表达式方法
* @param ex 中缀表达式
* @return 后缀表达式栈
*/
private String getAfterExpress(String ex) {
// 得到元素数组
String[] spilt = getArray(ex);
// 遍历数组
for (String c : spilt) {
// 得到元素类型
int numOrsym = getType(c);
switch (numOrsym) {
// 1为数字,存入表达式栈
case 1:
exp.push(c + "");
break;
// 其他则进行符号判定,之后存入表达式栈
default:
// 进行符号判定
checkSym();
// 存入表达式栈
sym.add(c);
break;
}
}
// 符号优先级插入运算,用于将剩余符号进行运算插入后最表达式栈
highLevel(sym);
// 讲后缀表达式栈转换为字符串
String ae = "";
for (Iterator iterator = exp.iterator(); iterator.hasNext();) {
ae = ae + iterator.next();
}
// 返回字符串
return ae;
}
/**
* 表达式分解数组方法
* @param ex 中缀表达式
* @return 元素数组
*/
private String[] getArray(String ex) {
String[] split = ex.split(" ");
return split;
}
/**
* 符号判定
*/
private void checkSym() {
// 符号栈内元素超过一个时进入
if (sym.size() > 1) {
// 符号栈内包含左括号时进入
if (sym.contains("(")) {
// 如果符号栈内包含右括号,并且右括号为栈顶元素时进入
if (sym.contains(")") && sym.indexOf(")") + 1 == sym.size()) {
// 缓冲变量
String i;
// 创建括号内符号缓冲栈
Stack<String> buffer = new Stack<String>();
// 取出元素不等于左括号时运行
while (!(i = sym.pop()).equals("(")) {
// 取出元素如果为右括号,结束本次循环,进入下次循环
if (i.equals(")"))
continue;
// 将符号存入符号缓存栈
buffer.push(i);
}
// 将符号缓存栈进行优先级运算,并存入后缀表达式栈
highLevel(buffer);
}
// 符号栈内不包含括号,并且符号元素为两个时进行运算
} else if (sym.size() == 2) {
// 将符号栈元素运算至后缀表达式栈
popSym();
}
}
}
/**
* 符号栈内多符号元素的优先级运算方法
* 运算后存入后缀表达式栈
* @param buffer 符号栈
*/
private void highLevel(Stack<String> buffer) {
// 包含乘除法时
while (buffer.contains("*") | buffer.contains("/")) {
// 如果包含乘法
if (buffer.contains("*")) {
// 符号栈移除乘号
buffer.removeElement("*");
// 后缀表达式栈存入乘号
exp.push("*" + "");
}
// 如果包含除法
if (buffer.contains("/")) {
// 符号栈溢出除号
buffer.removeElement("/");
// 后缀表达式栈存入除号
exp.push("/" + "");
}
}
// 剩余符号,无序存入后缀表达式栈
while (buffer.size() != 0) {
exp.push(buffer.pop() + "");
}
}
/**
* 符号栈内两元素优先级运算方法
* 运算后存入后缀表达式
*/
private void popSym() {
// 取出第一个符号
String a1 = sym.pop();
// 取出第二个符号
String a2 = sym.pop();
// 通过符号类型运行优先级
if (getType(a1) > getType(a2)) {
exp.push(a1 + "");
exp.push(a2 + "");
} else {
exp.push(a2 + "");
exp.push(a1 + "");
}
}
/**
* 元素类型及符号优先级运算
* @param word 元素
* @return
*/
private int getType(String word) {
// 取出首位符号(主要用于辨别数字与符号)
char[] cs = word.substring(0, 1).toCharArray();
// 默认辨识符
char one = '`';
if (cs.length == 1) {
// 首位符号作为辨识符
one = cs[0];
}
// 如果首位元素的ascii码在0-9之间则为数字
if (one >= '0' && one <= '9') {
return 1;
}
// 否则则为符号
else {
switch (word) {
case "(":
return 41;
case ")":
return 42;
case "*":
return 31;
case "/":
return 32;
case "+":
return 21;
case "-":
return 22;
default:
throw new RuntimeException(word + "字段错误");
}
}
}
}