Java中缀表达式转后缀表达式完成逆波兰计算

首先,逆波兰表达式又叫做后缀表达式

逆波兰算法的核心步骤就2个:
1、将中缀表达式转换为后缀表达式,
2、根据后缀表达式,按照特定的计算规则得到最终计算结果

步骤一思路:
中缀表达式转后缀表达式:

  • 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中的元素并输出。结构的逆序即为中缀表达式对应的后缀表达式
    有了思路代码如下
package com.xu.stack;
import javax.security.auth.Subject;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class infixConvertedToSuffix {
    public static void main(String[] args) {
        //完成一个中缀表达式转成后缀表达式的代码
        //说明
        //1. +=> 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";
        List<String>infixExpressionList =toInfixExpressionList(expression);
        System.out.println(infixExpressionList);
        System.out.println(parseSuffixExpressionList(infixExpressionList));
    }
    //方法 将中缀表达式转成对应的List
    public  static List<String> toInfixExpressionList(String s){
        //定义一个List,存放中缀表达式对应的内容
        List<String> ls=new ArrayList<String>();
        int i=0;//这个相当于一个指针 用于遍历 中缀表达式字符串
        String str; //这个对多位数的一个拼接工作
        char c; //每遍历到一个字符 就放入到c
        do{
            //如果c是一个非数字 我需要加入到ls
            if ((c=s.charAt(i))<48||(c=s.charAt(i))>57){  //asc2码表48到57 表示0到9
                ls.add(""+c);
                i++;//i 需要后移
            }else {
                //如果是一个数 需要考虑多位数的问题
                str="";//先将str 制空
                while (i<s.length()&&(c=s.charAt(i))>=48&& (c=s.charAt(i))<=57){  //将i指针后移 并判断是否为数字
                    str+=c;//拼接
                    i++;
                }
                ls.add(str);
            }
        }while (i<s.length());
        return ls;
    }
    //方法:将得到的一个中缀表达式对应的List =>转成后缀表达式对应的List
    public  static  List<String> parseSuffixExpressionList(List<String>ls){
        //定义两个栈
        Stack<String> s1=new Stack<String>(); //符号栈
        //说明:因为s2这个栈 在整个转换过程中 没有pop操作,而且后面我们还需要逆序操作
        //因此比较麻烦。这里我们就不用栈 而直接用List
        //Stack<String> s2=new Stack<String>(); //储存中间结果的栈
        List<String>s2 =new ArrayList<String>();//储存中间结果

        //遍历ls
        for (String item:ls) {
            //如果是一个数,就加入s2
            if (item.matches("\\d+")){
                s2.add(item);
            }else if (item.equals("(")){
                s1.push(item);
            }else if (item.equals(")")){
                // 如果是右括号")",则一次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一括号丢弃
                while (!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//  将(弹出 s1栈 消除小括号
            }else {
                //当 item的优先级小于等于s1栈顶运算符,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-(1))与s1中新的栈顶运算符相比较
                //问题 缺少一个比较优先级高低的方法
                while (s1.size()!=0&&Operation.getValue(s1.peek())>=Operation.getValue(item)){
                    s2.add(s1.pop());
                }
                //还需要将item压入栈
                s1.push(item);
            }
        }
        //将s1剩余的运算符依次弹出并加入s2
        while (s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;
    }

}
//编写一个类 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:
                System.out.println("不存在改运算符");
                break;


        }
        return result;
    }
}

代码运行结果
在这里插入图片描述
将得到的逆波兰表达式取出 也就是 :1, 2, 3, +, 4, *, +, 5, -
完成逆波兰表达式运算思路:

  • 从左至右扫描,将1,2和3压入堆栈
  • 遇到+运算符 ,因此弹出3和2 (3为栈顶元素,2为次顶元素),计算出3+2的值 ,得5.再将5入栈;
  • 遇到4 再将4入栈
  • 遇到运算符 将4 和5出战计算输45的值 得20,将20入栈 此时栈内只有1 和20
  • 遇到 + 号之后 1 和20 出栈相加 得21
  • 继续向右扫描遇到 将5入栈 遇到 -运算符 弹出21 和5 计算21-5得16就为最终结果

代码实现如下

package com.xu.stack;

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

public class PolandNotation {
    public static void main(String[] args) {
        String suffixExpression="1 2 3 + 4 * + 5 -";

        List<String>rpnList=getListString(suffixExpression);
        System.out.println("rpnList="+rpnList);

        int res=calculate(rpnList);
        System.out.println(res);

    }

    //将一个逆波兰表达式,依次将数据和运算符 放入到ArrayList中
    public  static List<String> getListString(String suffixExpression){
        //将 suffixExpression 分割
        String[] split =suffixExpression.split(" ");
        List<String> list =new ArrayList<String>();
        for (String ele:split) {
            list.add(ele);
        }
        return list;
    }

    public  static  int calculate(List<String>ls){
        //创建给栈,只需要一个栈即可0

        Stack<String> stack=new Stack<String>();

        //遍历 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("运算符有误");
                }
                //把res入栈
                stack.push(res+"");
            }

        }
        //最后留在stack中的数据就是运算结果
        return  Integer.parseInt(stack.pop());
    }
}

运行结果图片如下:
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值