栈的应用之逆波兰计算器练习

创建操作运算符的类

public 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:
                break;
        }
        return result;
    }
}

计算器

逆波兰表达式,在逆波兰记法中,所有操作符置于操作数的后面,所以逆波兰表示又称后缀表达式。逆波兰记法不需要括号来标识操作符的优先级。

将中缀表达式转成后缀表达式

将中缀表达式转后后缀表达式需要用到两个栈,一个是符号栈,一个是结果栈。
先将表达式转成List类型(我这里表达式写的是String类型,转成List好操作)

    //将中缀表达式转成list,拆分中缀表达式
    public static List<String> toInfixExpressionList(String s){
        ArrayList<String> expression = new ArrayList<String>();
        int i = 0;   //用于遍历中缀表达式
        String keepNum = "";  //用于拼接多位数
        char ch;   //存放遍历得到的符号和数
        do{
            if((ch = s.charAt(i)) < 48 || (ch = s.charAt(i)) > 57){   //如果不是数字
                expression.add("" + ch);
                i++;
            }else{  //如果是数字的话,就要考虑多位数的问题了
                keepNum = "";   //要把keepNum置成空串,这部需要注意
                while(i < s.length() && (ch = s.charAt(i)) >= 48 && (ch = s.charAt(i)) <= 57){
                    keepNum += ch;
                    i++;
                }
                expression.add(keepNum);
            }
        }while(i < s.length());
        return expression;
    }

然后就可以进行转换了,举例:
在这里插入图片描述
从左往右扫描中缀表达式,扫描到第一个是"(",直接压入符号栈
在这里插入图片描述
继续扫描,扫描到数字,直接入结果栈
在这里插入图片描述
继续扫描,扫描到"+",由于符号栈栈顶是"(",不需要比较运算符优先级,直接将"+“压入符号栈中
在这里插入图片描述
继续扫描,遇到数字2,直接压入栈中
在这里插入图片描述
继续扫描,遇到”)",弹出符号栈中的运算符压入结果栈中去,直到遇到"(",同时将此时符号栈栈顶的"(“弹出,一对括号就消除掉了
在这里插入图片描述
继续扫描,扫描到”*",此时符号栈为空,可以直接压入符号栈中
在这里插入图片描述
继续扫描,数字直接压入结果栈中
在这里插入图片描述
继续扫描,遇到运算符"+",此时符号栈不为空,此时需要和符号栈栈顶的运算符进行优先级的比较,如果此时运算符的优先级大于符号栈栈顶运算符的优先级可以直接将该运算符压入符号栈,否则需要将符号栈栈顶的运算符压入结果栈中,再次与符号栈栈顶的运算符进行比较,反复上述操作,直到优先级大于符号栈栈顶运算符的优先级,就将该运算符压入符号栈中。
在这里插入图片描述
继续扫描,是数字,直接压入结果栈在这里插入图片描述
扫描结束,将符号栈中的运算符依次压入结果栈中
在这里插入图片描述
将结果栈中的元素依次弹出,结果的逆序就是后缀表达式

    public static List<String> toSuffixExpreesionList(String infixExpression){
        List<String> s = toInfixExpressionList(infixExpression);
        Stack<String> s1 = new Stack<>();    //符号栈
        List<String> s2 = new ArrayList<>();    //存储结果的栈,因为逆序的结果的后缀表达式,所以直接用List不需要再次逆序拿出来
        for(String item : s){
            //如果是一个数,直接入栈
            if(item.matches("\\d+")){
                s2.add(item);
            }else{
                if(s1.isEmpty() || s1.peek() == "("){ //如果栈为空或者栈顶是"(",符号直接入栈
                    s1.push(item);
                }else if(item.equals(")")){   //如果是")",依次弹出s1的运算符,压入s2中,直到遇到"("为止,将这一对括号丢弃
                    while(!s1.peek().equals("(")){
                        s2.add(s1.pop());
                    }
                    s1.pop();   //消除"("一对括号被丢弃
                }else{
                    while(s1.size() != 0 && Operation.getValue(item) <= Operation.getValue(s1.peek())){
                        //如果item的优先级小于s1栈顶的优先级,就将符号栈栈顶的运算符压入s2中
                        s2.add(s1.pop());
                    }
                    s1.push(item);  //最后将item压入符号栈中
                }
            }
        }
        //将符号栈中剩余的运算符压入最后的结果栈中
        while(!s1.isEmpty()){
            s2.add(s1.pop());
        }
        return s2;
    }

计算器实现

计算器的实现只需要一个站
依次扫描后缀表达式,数字直接压入栈中,遇到运算符从栈中压入两个数进行运算,将结果再次压入栈中,继续扫描
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

    public static int PolandNotationcalculator(String expression){
        List<String> list = toSuffixExpreesionList(expression);
        Stack<String> stack = new Stack<>();
        for(String item : list){
            if(item.matches("\\d+")){  //如果是数字,则直接入栈
                stack.push(item);
            }else{                      //如果是运算符,从栈中弹出两个数进行运算,将运算结果再次压入栈中
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int result = 0;
                if(item.equals("+")){
                    result = num1 + num2;
                }else if(item.equals("-")){
                    result = num1 - num2;
                }else if(item.equals("/")){
                    result = num1 / num2;
                }else if(item.equals("*")){
                    result = num1 * num2;
                }else{
                    throw new RuntimeException("符号错误");
                }
                stack.push("" + result);
            }
        }
        return Integer.parseInt(stack.pop());
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ht巷子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值