关于怎么求数学表达式的值,网上有很多教程。但大多教程只是一个Demo,该Demo只实现了个位数的四则运算,遇到个位数以上的计算时就会出现问题。本文在此基础上进行了扩展,实现了个位数以上的四则运算。
整体思路:
输入的表达式为中缀表达式,将该表达式转为后序表达式然后利用栈做运算。
中缀表达式转后缀表达式的方法:(用list存放后缀表达式中各元素,用栈stack临时存放运算符)
1:遇到数字时:将其放入list。
2:遇到运算符时:当运算符时乘号或者除号时直接入栈。当运算符时加减号时:若栈为空则直接入栈;否则,获取栈顶运算符topOper(是获取,而不是弹出,故用peek而不是pop),若topOper为左括号时,直接入栈,否则循环获取栈中左括号上面的元素加入list,最后将当前运算符入栈。
3:遇到左括号(“(”)时,直接入栈;
4:遇到右括号时(“)”),依次出栈,当出栈运算符为左括号时,退出。
5:最终将栈中的各元素依次出栈放入list。
使用后缀表达式求值的方法:
依次遍历list中的各元素进行入栈,当得到的元素为运算符时,取出栈顶的两个元素做运算,然后将运算结果入栈,直到list遍历完成。
代码如下:
import java.util.*;
public class MyStackCalculators {
public static void main(String[] args) {
String string = "(7+4*3+10*(3-3+4-1-8-10))";
List<String> inputList = strToList(string);
List<String> postfix = getPostfixExpression(inputList);
String res = getRes(postfix);
System.out.println("最终结果为:" + res);
}
/**
* 获取输入表达式中的各元素,并用list进行存储。
* @param expression
* @return
*/
private static List<String> strToList(String expression) {
List<String> arrayList = new ArrayList<String>();
char ch[] = expression.toCharArray();
String v = "";
for(int i=0; i<ch.length; i++) {
char e = ch[i];
if(e >= '0' && e <= '9') {
v += e;
} else {
if(v != "") {
arrayList.add(v);
}
arrayList.add(e + "");
v = "";
}
}
if(v != "") {
arrayList.add(v);
}
return arrayList;
}
private static List<String> getPostfixExpression(List<String> list) {
List<String> pfixExpList = new ArrayList<>();//存放后缀表达式中各元素的list
Stack<String> stack = new Stack<>();//存放运算符的栈
for(int i=0; i<list.size(); i++) {
String tm = list.get(i);
if(tm.matches("[0-9]*")) {//当得到的元素是数字时,直接放入list。
pfixExpList.add(tm);
} else if(tm.equals("(")) {//当得到元素是左括号时,直接入栈
stack.push(tm);
} else if(tm.equals(")")){//当得到元素是右括号时
//执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
String s = stack.pop();
while(!(s.equals("(")) && !stack.isEmpty()) {
pfixExpList.add(s);
s = stack.pop();//此语句最终会弹出左括号
}
} else { //是运算符
if(tm.equals("*") || tm.equals("/")) { //乘号和除号情况,直接入栈
stack.push(tm);
} else {//加减号情况,取出栈中的“(”上面的全部元素存入list1,最后将当前运算符入栈
if(stack.isEmpty()) {
stack.push(tm);
} else {
String s = stack.peek();
if(s.equals("(")) {
stack.push(tm);
} else {
while(!s.equals("(") && !stack.isEmpty()) {
pfixExpList.add(stack.pop());
s = stack.peek();
}
stack.push(tm);//将当前运算符入栈
}
}
}
}
}
//将栈中剩余元素存入list
while(!stack.isEmpty()) {
pfixExpList.add(stack.pop());
}
return pfixExpList;
}
/**
* 得到表达式的最终值
* @param list 存放的后缀表达式各元素
* @return
*/
private static String getRes(List<String> list) {
Stack<String> stack = new Stack<String>();//存放结果用
for(int i=0; i<list.size(); i++) {
String el = list.get(i);
if(el.matches("[0-9]*")) {//若为数字,直接入栈。
stack.push(el);
} else {//若不为数字,则取出栈顶的两个元素做运算,并将结果入栈
int v1 = 0;
int v2 = 0;
int res = 0;
switch(el) {
case "+":
v2 = Integer.valueOf(stack.pop());
v1 = Integer.valueOf(stack.pop());
res = (v1 + v2);
stack.push(res+"");
break;
case "-":
v2 = Integer.valueOf(stack.pop());
v1 = Integer.valueOf(stack.pop());
res = (v1 - v2);
stack.push(res+"");
break;
case "*":
v2 = Integer.valueOf(stack.pop());
v1 = Integer.valueOf(stack.pop());
res = (v1 * v2);
stack.push(res+"");
break;
case "/":
v2 = Integer.valueOf(stack.pop());
v1 = Integer.valueOf(stack.pop());
res = (v1 / v2);
stack.push(res+"");
break;
}
}
}
return stack.pop();
}
}
运行结果如下:
最终结果为:-131
注:关于这代码还有一个问题就是当表达式中有乘和除连续的时候,是按照其出现的顺序计算的,这会导致1/3*3为0的情况。