中缀表达式转后缀表达式(逆波兰表达式) java详细讲解

中缀表达式转后缀表达式(逆波兰表达式) java详细讲解

为什么需要转换

大家看到,后缀表达式适合计算式进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将 中缀表达式转成后缀表达式

在这里插入图片描述

具体的步骤

  1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压s2;
  4. 遇到运算符时,比较其与s1栈顶运算符的优先级:
    1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
    3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较;
  5. 遇到括号时:
    (1) 如果是左括号“(”,则直接压入s1
    (2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
  6. 重复步骤2至5,直到表达式的最右边
  7. 将s1中剩余的运算符依次弹出并压入s2
  8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

举例说明

将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下,因此结果为 “1 2 3 + 4 × + 5 –”
在这里插入图片描述

解题思路

在这里插入图片描述

代码实现

package com.qf.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNation {
    public static void main(String[] args) {
        //(55+6)*2+33-12
        String expression="(55+6)*2+33-12";
        List<String> splitList = getSplitList(expression);
        List<String> sufferList = getSufferList(splitList);
        int cal = cal(sufferList);
        System.out.println("计算得到的结果:"+cal);
    }

    public static List<String> getStringList(String express){
        String[] split = express.split(" ");
        List<String> list=new ArrayList<>();
        for (String s : split) {
            list.add(s);
        }
        return list;
    }

    /*从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,
    用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;
    重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
     */
    public static int cal(List<String> list){
        Stack<String> stack=new Stack<>();

        for (String item : list) {
            if (item.matches("\\d+")){
                stack.push(item);
            }else{
                int num1 = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int res=0;
                switch (item){
                    case "+":
                        res=num1+num2;
                        break;
                    case "-":
                        res=num2-num1;
                        break;
                    case "*":
                        res=num1*num2;
                        break;
                    case "/":
                        res=num2/num1;
                        break;
                    default:
                        break;
                }
                stack.push(""+res);
            }
        }

        int res=Integer.parseInt(stack.pop());
        return res;
    }

    //获取中缀表达式的拆分
    public static List<String> getSplitList(String express){
        List<String> list=new ArrayList<>();
        int i=0;
        String str;
        do {
            if (express.charAt(i)>57||express.charAt(i)<48){
                list.add(String.valueOf(express.charAt(i)));
                i++;
            }else{
                str="";
                while (i<express.length()&&express.charAt(i)<=57&&express.charAt(i)>=48){
                    str=str+express.charAt(i);
                    i++;
                }
                list.add(str);
            }
        }while (i<express.length());
        return list;
    }

    //1 + ( ( 2 + 3 )× 4) - 5
    //把中缀表达式转换为后缀表达式
   /* 1) 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
            2) 从左至右扫描中缀表达式;
            3) 遇到操作数时,将其压s2;
            4) 遇到运算符时,比较其与s1栈顶运算符的优先级:
            1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
            2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
            3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较;
            5) 遇到括号时:
            (1) 如果是左括号“(”,则直接压入s1
            (2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
     6) 重复步骤2至5,直到表达式的最右边
     7) 将s1中剩余的运算符依次弹出并压入s2
     8)  依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式*/
    public static List<String> getSufferList(List<String> list){
        //运算符栈s1
        Stack<String> operateStack=new Stack<>();

        //中间结果 使用ArrayList的原因是因为可以减少后缀表达式的逆序
        List<String> tempList=new ArrayList<>();
        for (String item : list) {
            if (item.matches("\\d+")){
                tempList.add(item);
            } else if (item.equals("(")){
                operateStack.push(item);
            }else if (item.equals(")")){
                while(!operateStack.peek().equals("(")){
                    tempList.add(operateStack.pop());
                }
                operateStack.pop();
            }else{
                while(operateStack.size()!=0&&Operation.getPrior(item)<=Operation.getPrior(operateStack.peek())){
                    tempList.add(operateStack.pop());
                }
                operateStack.push(item);
            }

        }

        while (operateStack.size()!=0){
            tempList.add(operateStack.pop());
        }
        return tempList;
    }
}
class Operation{
    public static final int DEV=2;
    public static final int MUL=2;
    public static final int DEC=1;
    public static final int ADD=1;

    public static int getPrior(String rex){
        int res=0;
        switch (rex){
            case "+":
                res=ADD;
                break;
            case "-":
                res=DEC;
                break;
            case "*":
                res=MUL;
                break;
            case "/":
                res=DEV;
                break;
            default:
                System.out.println("未匹配字符");
                break;
        }
        return res;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

舒克日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值