“携手创作,共同成长!开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情”
中缀表达式转换为后缀表达式
后缀表达式适合计算式进行运算,尤其是表达式很长的情况下,因此在开发中,需要将中缀表达式转成后缀表达式。
思路分析:
1.由于直接对str进行操作不方便,因此先将“1+((2+3)*4)-5”转换成中缀表达式对应的list
即“1+((2+3)4)-5”转换成ArrayList[1,+,(,(,2,+,3,),,4,),-,5]
2.已经可以将ArrayList转换成后缀表达式了,使用上面的八步方法就可以实现,但不同的是在第一步创建两个栈的过程中,将其中那个存放最终结果的栈可以使用list链表进行替代,只有进去数据,没有数据出去的操作。因为如果是栈(先进后出)最后需要倒序输出,而链表可以直接输出,就是所需要的结果。
代码实现:
public static List<String> parseSuffixExpressionList(List<String> s){
//初始化两个栈
Stack<String> s1 = new Stack<String>(); //进行中转的栈
//其中那个存放最终结果的栈可以使用list链表进行替代,只有进,没有出去的操作
// 因为如果是栈(先进后出)最后需要倒序输出,而链表可以直接输出,就是所需要的结果。
//Stack<String> s2 = new Stack<String>(); //存储最终结果的栈
List<String> s2 = new ArrayList<String>(); //存储最终结果的List
//开始从左到右遍历中缀表达式
for (String item : s) {
//遇到操作数时,将其入栈s2;
if (item.matches("\\d+")){
s2.add(item);
} //遇到运算符时,比较其与s1栈顶运算符的优先级:
// (1)如果s1为空,或栈顶运算符为左括号“(",则直接将此运算符入栈;
// 遇到括号时:
// (1)如果是左括号“(”,则直接压入s1
// (2)如果是右括号“)",则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
// (2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
// (3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较;
else if(s1.isEmpty()||item.equals("(")){
s1.push(item);
} else if(item.equals(")")) {
//依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
while (!s1.peek().equals("(")){
s2.add(s1.pop());
}
//一定要有这一句,将最后一个小括号弹出,因为判断是遇见了这个括号,而我们要删除这个括号
s1.pop();
} else {
// 若优先级比栈顶运算符的相等或者低,栈顶的运算符弹出并压入到s2中;
// s1一定不能为0,若是0就没办法再压了
while (s1.size()!=0 &&Operation.getValue(s1.peek())>=Operation.getValue(item)){
s2.add(s1.pop());
}
//若优先级比栈顶运算符的高,也将运算符压入s1;或者在执行完上一步操作后,也需要将本运算符添加进去
s1.push(item);
}
}
//将s1中剩余的运算符依次弹出并加入到s2中
while (s1.size()!=0){
s2.add(s1.pop());
}
return s2; //因为是存放到List,因此逆序输出就是对应的后缀表达式
}
//将一个逆波兰表达式,依次将数据和符号放入一个ArrayList中
public static List<String> getlistString(String suffixExpression){
String[] split = suffixExpression.split(" ");
List<String> list=new ArrayList<String>();
for (String ele:split){
list.add(ele);
}
return list;
}
//完成对逆波兰表达式的运算
public static int calcluate(List<String> ls){
//创建栈,只需要一个栈即可
Stack<String> stack = new Stack<>();
//遍历 ls
for (String item:ls) {
//使用正则表达式来判断数据是否是数字,若是数字就进行入栈
if(item.matches("\\d+")) {
stack.push(item);
} else { //若不是数,就是符号,进行出栈操作,
int num1=Integer.parseInt(stack.pop()); //将字符转换成数字
int num2=Integer.parseInt(stack.pop()); //将字符转换成数字
int res=0; //存入结果
if(item.equals("+")){
res=num2+num1; //要进行换序操作
} else if(item.equals("-")){
res=num2-num1; //要进行换序操作
} else if(item.equals("*")){
res=num2*num1; //要进行换序操作
} else if(item.equals("/")){
res=num2/num1; //要进行换序操作
} else {
throw new RuntimeException("运算符有错误");
}
//把res 入栈
stack.push(""+res); //通过前面加""可以直接将结果直接变成字符串类型的
}
}
//最后将留在stack的最后结果进行输出,最后别忘了将字符串类型的数字转成整型
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:
}
return result;
}
}