中缀表达式求值(Java)
通常使用的是中缀表达式,例如:2+(3-1)*2;计算中缀表达式一般先转换成后缀表达式,后计算;
中缀表达式
中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)
- 中缀表达式的求解需要两个栈来存储,且设置为泛型,一个栈存操作数,一个栈存操作符,需要输入一个表达式字符串并将其转为字符串数组以提取有效字符。
后缀表达式
- 后缀表达式求解: 从左到右扫描后缀表达式,若遇操作数,则进栈;若遇运算符,则从栈中退出两个元素,先退出的放到运算符的右边,后退出的 放到运算符左边,运算后的结果再进栈,直到后缀表达式扫描完毕。此时,栈中仅有一个元素,即为运算的结果。
中缀表达式转后缀表达式思路
1.定义两个栈,一个stack栈结构存储操作符,一个List结构存储后缀表达式结果
2.首先读取到数字,直接存入list中
3.当读取到左括号"("时,直接压栈,当读取到运算符时,分以下两种情况讨论
1.当运算符栈为空或者栈顶操作符的优先级小于当前运算符优先级时(如+和-的优先级低于 * 和 /),直接入栈
2.当运算符不为空时且栈顶操作符的优先级大于或等于当前运算符优先级时,循环执行出栈操作并加入list中,直到遇到优先级小于当前运算符的元素为止。循环执行完后再将当前运算符压栈。另外需要注意的是,只有遇到右括号时,左括号才出栈
4.当遇到右括号")"时,循环执行出栈操作并加入到list中,直到遇到左括号为止。并将左括号弹出,但不加入list中
5.表达式的值读取完后,将操作符栈中的所有元素弹出并加入到list中
代码如下
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;
public class Calculator {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String expression = sc.nextLine();
List<String> infixexpression = Depositlist(expression);//中缀表达式
System.out.println("中缀表达式为:"+ infixexpression );
List<String> calculateexpression = parsexpreesion(infixexpression);//后缀表达式
System.out.println("后缀表达式为:"+calculateexpression);
System.out.printf("Answer=%d", calculate(calculateexpression)); //计算结果
}
public static List<String> parsexpreesion(List<String> list) {//方法:将得到的中缀表达式对应的转换后缀表达式对应的List
//定义两个栈
Stack<String> s1 = new Stack<String>(); // 符号栈
List<String> s2 = new ArrayList<String>(); // 储存中间结果的Lists2
for(String item: list ) {
if(item.matches("\\d+")) {//如果是一个数加入s2
s2.add(item);
} else if (item.equals("(")) {
s1.push(item);
} else if (item.equals(")")) {
while(!s1.peek().equals("(")) {//如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
s2.add(s1.pop());
}
s1.pop();//将 ( 弹出 s1栈, 消除小括号
} else {
while(s1.size() != 0 && operation.getValue(s1.peek()) >= operation.getValue(item) ) {
s2.add(s1.pop());
}
s1.push(item);
}
}
while(s1.size() != 0) { //将s1中剩余的运算符依次弹出并加入s2
s2.add(s1.pop());
}
return s2;
}
public static List<String> Depositlist(String s) {
List<String> list = new ArrayList<String>();//定义一个List,存放中缀表达式 对应的内容
int i = 0;
String str;
char c;
do {
if((c=s.charAt(i)) < 48 || (c=s.charAt(i)) > 57) {
list.add("" + c);
i++;
} else {
str = ""; //先将str 置成"" '0'[48]->'9'[57]
while(i < s.length() && (c=s.charAt(i)) >= 48 && (c=s.charAt(i)) <= 57) {
str += c;
i++;
}
list.add(str);
}
}while(i < s.length());
return list;
}
//将一个逆波兰表达式, 依次将数据和运算符 放入到 ArrayList中
public static List<String> getListString(String suffixexpression) {
String[] split = suffixexpression.split(" ");//将 suffixexpression 分割
List<String> list = new ArrayList<String>();
for(String ele: split) {
list.add(ele);
}
return list;
}
public static int calculate(List<String> list) {
Stack<String> stack = new Stack<String>();// 创建栈
for (String item : list) {
if (item.matches("\\d+")) { //使用正则表达式匹配多位数
stack.push(item);
} else {
int num2 = Integer.parseInt(stack.pop()); // pop出两个数,并运算, 再入栈
int num1 = Integer.parseInt(stack.pop());
int res = 0;
if (item.equals("+")) {
res = num1 + num2;
} else if (item.equals("-")) {
res = num1 - num2;
} else if (item.equals("*")) {
res = num1 * num2;
} else if (item.equals("/")) {
res = num1 / num2;
} else {
throw new RuntimeException("运算符有误");
}
stack.push("" + res);
}
}
return Integer.parseInt(stack.pop());
}
}
//编写一个类 Operation 可以返回一个运算符 对应的优先级
class operation {
private static int Add = 1;
private static int Sub = 1;
private static int Mul = 2;
private static int Div = 2;
//写一个方法,返回对应的优先级数字
public static int getValue(String operation) {
int result = 0;
switch (operation) {
case "+":
result = Add;
break;
case "-":
result = Sub;
break;
case "*":
result = Mul;
break;
case "/":
result = Div;
break;
default:
break;
}
return result;
}
}
运行结果
1+2*(6-3)-6/2
中缀表达式为:[1, +, 2, *, (, 6, -, 3, ), -, 6, /, 2]
后缀表达式为:[1, 2, 6, 3, -, *, +, 6, 2, /, -]
Answer=4