主要介绍了我们接触的前缀,中缀,后缀表达式
中缀表达式即为我们平时写出的计算式
后缀表达式是计算机运算的计算排列顺序
需求:
逆波兰计算器就是将我们给定的中缀表达式先转化为后缀表达式,再进行后缀表达式的计算过程。
代码实现:
1)先将中缀表达式(String)转化为list类型存储
//方法:将 中缀表达式转成对应的List
// s="1+((2+3)×4)-5";
public static List<String> toInfixExpression(String s){
List<String> ls = new ArrayList<String>();
int i = 0;//定义一个指针
String str;//用于多位数拼接
char c;
do {
//如果c是一个非数字,我需要加入到ls
if ((c = s.charAt(i)) < 48|| (c = s.charAt(i)) > 57){
ls.add(""+c);
i++;//后移
}else{//如果是一个数,需要考虑多位数
str = "";//每次都要清空一下
while(i < s.length()&& (c = s.charAt(i))>=48&&(c = s.charAt(i))<=57){
str += c;//多位数拼接
i++;
}
ls.add(str);
}
}while (i < s.length());
return ls;//返回
}
2)将中缀表达式转化为后缀表达式:
图解:
思路:
代码实现:
//方法:将得到的中缀表达式对应的List => 后缀表达式对应的List
public static List<String> parseSuffixExpressionList(List<String> ls){
Stack<String> s1 = new Stack<String>();//定义一个符号栈
List<String> s2 = new ArrayList<String>();//定义一个储存中间结果的集合,避免用栈逆序输出
for (String item : ls) {
if (item.matches("\\d+")){
s2.add(item);//如果是一个数直接加进s2
}else if(item.equals("(")){
s1.push(item);
}else if (item.equals(")")){
//如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
while(!s1.peek().equals("(")){
s2.add(s1.pop());
}
s1.pop();//消除一组括号
}else{
//当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较
//问题:我们缺少一个比较优先级高低的方法
while(s1.size() != 0 && Operation.getValue(item) <= Operation.getValue(s1.peek())){
s2.add(s1.pop());
}
s1.push(item);//把运算符压入栈中
}
}
//将s1中剩余的运算符依次弹出并加入s2
while(s1.size()!=0){
s2.add(s1.pop());
}
return s2; //注意因为是存放到List, 因此按顺序输出就是对应的后缀表达式对应的List
}
3)逆波兰计算器的运算
思路:
public static int calculate(List<String> ls){
//创建一个栈
Stack<String> stack = new Stack<>();
//对ls进行遍历
for (String item : ls) {
//使用正则表达式取出数
if (item.matches("\\d+")){//匹配的是多位数
stack.push(item);//把数放进栈中
}else{
//否则就pop出两个数进行运算
int num2 = Integer.parseInt(stack.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());
}
}
4)定义一个判断运算符优先级的类别:
/**
* 定义一个判断优先级的类
*/
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 key){
int res = 0;
switch (key){
case "+":
res = ADD;
break;
case "-":
res = SUB;
break;
case "*":
res = MUL;
break;
case "/":
res = DIV;
break;
default:
System.out.println("不存在该运算符"+key);
break;
}
return res;
}
}
5)测试:
public class PolandNotation {
public static void main(String[] args) {
//完成将一个中缀表达式转成后缀表达式的功能
//说明
//1. 1+((2+3)×4)-5 => 转成 1 2 3 + 4 × + 5 –
//2. 因为直接对str 进行操作,不方便,因此 先将 "1+((2+3)×4)-5" =》 中缀的表达式对应的List
// 即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
//3. 将得到的中缀表达式对应的List => 后缀表达式对应的List
// 即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5] =》 ArrayList [1,2,3,+,4,*,+,5,–]
String expression = "1+((2+3)*4)-5";//16
List<String> infixExpression = toInfixExpression(expression);
System.out.println("infixExpression="+infixExpression);
List<String> suffixExpressionList = parseSuffixExpressionList(infixExpression);
System.out.println("suffixExpressionList="+suffixExpressionList);
System.out.println(calculate(suffixExpressionList));
/*
//说明为了方便,逆波兰表达式 的数字和符号使用空格隔开
//String suffixExpression = "30 4 + 5 * 6 -";
//思路
//1. 先将 "3 4 + 5 × 6 -" => 放到ArrayList中
//2. 将 ArrayList 传递给一个方法,遍历 ArrayList 配合栈 完成计算
String suffixExpression = "30 4 + 5 * 6 -";
List<String> list = getListString(suffixExpression);
System.out.println("list="+list);
int res = calculate(list);
System.out.println("res = "+res);
*/
}