思路步骤
- 初始化两个栈:运算符栈s1和存储中间值的栈s2
- 从左至右扫描中缀表达式
- 遇到操作数压栈到s2
- 遇到运算符和s1栈顶元素比较优先级:
1.如果s1为空或栈顶元素为左括号则直接入栈
2.若优先级高则入栈s1
3.否则将s1栈顶元素压栈到s2,再循环1的判断
- 遇到括号时:
1.左括号压栈s1
2.右括号,则依次弹出s1元素压栈s2,直到遇到左括号,同时将这对括号丢弃
- 扫描直到表达式最右边,将s1元素依次压栈到s2
- s2弹栈的逆序就是后缀表达式
代码实现
public static List<String> convert(List<String> lst){
//s1是运算符栈
Stack<String> s1=new Stack<>();
List<String> s2=new ArrayList<>();
for (String s : lst) {
//正则表达式匹配浮点数
if(s.matches("[0-9]*\\.?[0-9]+")){
s2.add(s);
}else{
if(s1.empty()||s1.peek().equals("(")||"(".equals(s)){
s1.push(s);
}else if(")".equals(s)){
while (!"(".equals(s1.peek())){
s2.add(s1.pop());
}
s1.pop();
}else{
while (!s1.empty()&&operator(s)<=operator(s1.peek())){
s2.add(s1.pop());
}
s1.push(s);
}
}
}
while (!s1.empty()){
s2.add(s1.pop());
}
return s2;
}
支持四则运算、小括号、小数的计算器代码实现
- 先将表达式字符串转为List
public static List<String> toList(String str){
//去除空白字符,正则表达式匹配任意个空格
String[] space=str.split("\\s+");
String newStr="";
for (String s : space) {
newStr+=s;
}
//考虑小数点,小数点的ASCII码值是46
List<String> lst=new ArrayList<>();
for (int i = 0; i <newStr.length() ;) {
if(newStr.charAt(i)<48&&newStr.charAt(i)!=46||newStr.charAt(i)>57){
lst.add(newStr.charAt(i)+"");
i++;
}else{
String s="";
while (i <newStr.length()&&newStr.charAt(i)>=48&&newStr.charAt(i)<=57||
i <newStr.length()&&newStr.charAt(i)==46){
s+=newStr.charAt(i);
i++;
}
lst.add(s);
}
}
return lst;
}
- 规定运算符优先级
public static int operator(String str){
switch (str){
case "+":
case "-":
return 1;
case "*":
case "/":
return 2;
case "(":
return 0;
}
throw new RuntimeException("运算符不合法");
}
- 中缀表达式转后缀表达式如上(核心代码)。
- 后缀表达式计算
public static float cal(List<String> lst){
Stack<String> stringStack = new Stack<>();
for (String s : lst) {
//"\\d+"正则表达式匹配的是多位整数
if(!s.matches("[0-9]*\\.?[0-9]+")){
float num1=Float.parseFloat(stringStack.pop());
float num2=Float.parseFloat(stringStack.pop());
float res=0f;
switch(s){
case "+":
res=num1+num2;
break;
case "-":
res=num2-num1;
break;
case "*":
res=num1*num2;
break;
case "/":
res=num2/num1;
break;
}
//数字转字符串的小技巧
stringStack.push(res+"");
}else{
stringStack.push(s);
}
}
return Float.parseFloat(stringStack.pop());
}
ref :调度场算法