逆波兰表达式

逆波兰表达式

1、前言

看这边文章之前,我们首先要知道什么是逆波兰表达式。逆波兰表达式又叫做后缀表达式,是波兰的以为逻辑学家于1929年首先提出的一种表达式的表示方法。逆波兰表达式把运算量写在前面,把运算符写在后面。
我们知道逆波兰表达式又叫做后缀表达式,那么你是不是就有这样的猜想?是不是还有前缀表达式,没错,不仅仅有前缀表达式,还有中缀表达式,而中缀表达式是我们见过最多的一种。

  • 前缀表达式:前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。比如:- × + 3 4 5 6
  • 中缀表达式就是常见的运算表达式,如(3+4)×5-6
  • 后缀表达式:运算符位于操作数之后,就是 3 4 + 5 × 6 -

逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式

优势:
它的优势在于只用两种简单操作,入栈和出栈就可以搞定任何普通表达式的运算。其运算方式如下:
如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。

2、通过逆波兰表达式计算结果

在这里插入图片描述

将中缀表达式:3*(17-15)+18/6转为逆波兰表达式为:3 17 15 - * 18 6 / +
1、从左至右扫描,将3,17,15压入堆栈;
2、遇到-运算符,因此弹出15和17(15为栈顶元素,17为次顶元素),计算出17-15的值,得2,再将2入栈;
3、接下来是×运算符,因此弹出2和3,计算出2 x 3=6,将6入栈;
4、将18 6入栈
5、遇到 / 运算符,弹出6 和18,计算18/6=3,将3入栈,
6、最后是+运算符,计算出6+3的值,即9,由此得出最终结果(此时栈中只有一个数据)。

java代码实现

可以采用一个辅助的栈来实现计算,扫描表达式从左往右进行,如果扫描到数值,则压进辅助栈中,如果扫描到运算符,则从辅助栈中弹出两个数值参与运算,并将结果压进到栈中,当扫描表达式结束后,栈顶的数值就是表达式结果。

//逆波兰表达式
public class ReversePolishNotation {
    public static void main(String[] args) {
        //中缀表达式:3*(17-15)+18/6的逆波兰表达式如下
        String[] notation = {"3","17","15","-","*","18","6","/","+"};
        int result = caculate(notation);
        System.out.println("逆波兰表达式结果:"+result);
    }

    /**
     * @param notation 逆波兰表达式的数组表示方式
     * @return 逆波兰表达式的计算结果
     */
    private static int caculate(String[] notation) {
        //定义一个栈,用来存储操作数
        Stack<Integer> oprands = new Stack<>();
        //从左往右遍历逆波兰表达式
        for (int i = 0; i < notation.length; i++) {
            String curr = notation[i];
            //判断当前元素是运算符还是操作数
            Integer o1;
            Integer o2;
            Integer result;
            switch (curr){
                //如果是运算符,就从栈中弹起两个操作数,完成运算,并把运算完的结果在压入栈中
                case "+":
                     o1 = oprands.pop();
                     o2 = oprands.pop();
                     result = o2+o1;
                    oprands.push(result);
                    break;
                case "-":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2-o1;
                    oprands.push(result);
                    break;
                case "*":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2*o1;
                    oprands.push(result);
                    break;
                case "/":
                    o1 = oprands.pop();
                    o2 = oprands.pop();
                    result = o2/o1;
                    oprands.push(result);
                    break;
                default:
                    //如果是操作数,就把该操作数放入栈中
                    oprands.push(Integer.parseInt(curr));
                    break;
            }
        }
        //得到栈中最后一个元素,就是逆波兰表达式的结果
        int result = oprands.pop();
        return result;
    }
}

运算结果:
在这里插入图片描述
结果和我们分析的结果一致。

3、中缀表达式转换为后缀表达式(逆波兰表达式)

中缀表达式转后缀表达式主要用到了栈进行运算符处理,队列进行排序输出,规则为:

1、数字直接入队列
2、运算符要与栈顶元素比较

  • 栈为空直接入栈
  • 运算符优先级大于栈顶元素优先级则直接入栈
  • 小于或等于则出栈入列,再与栈顶元素进行比较,直到运算符优先级小于栈顶元素优先级后,操作符再入栈

3、操作符是 ( 则无条件入栈
4、操作符为 ) ,则依次出栈入列,直到匹配到第一个 ( 为止,此操作符直接舍弃,( 直接出栈舍弃

java代码实现:
/**
 * 中缀表达式转为后缀表达式
 */
public class PolishNotation {
    public static void main(String[] args) {
        String str = "1+((2+3)×4)-5";
        String transfer = transfer(str);
        System.out.println(transfer);
    }
    /**
     * 将中缀表达式转换为后缀表达式(逆波兰表达式)
     * @param express
     * @return
     */
    public static String transfer(String express){
        Stack<String> stack = new Stack<>();
        List<String> list= new ArrayList<>();
        for (int i=0;i<express.length();i++){
            if ((express.charAt(i)+"").matches("\\d")){
                list.add(express.charAt(i)+"");
            }else if((express.charAt(i)+"").matches("[\\+\\-\\*\\/]")){
                //如果stack为空
                if (stack.isEmpty()){
                    stack.push(express.charAt(i)+"");
                    continue;
                }
                //不为空
                //上一个元素不为(,且当前运算符优先级小于上一个元素则,将比这个运算符优先级大的元素全部加入到队列中
                while (!stack.isEmpty()&&!stack.lastElement().equals("(")&&!comparePriority(express.charAt(i)+"",stack.lastElement())){
                    list.add(stack.pop());
                }
                stack.push(express.charAt(i)+"");
            }else if(express.charAt(i)=='('){
                //遇到左小括号无条件加入
                stack.push(express.charAt(i) + "");
            }else if(express.charAt(i)==')'){
                //遇到右小括号,则寻找上一堆小括号,然后把中间的值全部放入队列中
                while(!("(").equals(stack.lastElement())){
                    list.add(stack.pop());
                }
                //上述循环停止,这栈顶元素必为"("
                stack.pop();
            }
        }
        //将栈中剩余元素加入到队列中
        while (!stack.isEmpty()){
            list.add(stack.pop());
        }
        StringBuffer stringBuffer = new StringBuffer();
        //变成字符串
        for (String s : list) {
            stringBuffer.append(s);
        }
        return stringBuffer.toString();
    }

    /**
     * 比较运算符的优先级
     * @param o1
     * @param o2
     * @return
     */
    public static boolean comparePriority(String o1,String o2){
        return getPriorityValue(o1)>getPriorityValue(o2);
    }

    /**
     * 获得运算符的优先级
     * @param str
     * @return
     */
    private static int getPriorityValue(String str) {
        switch(str){
            case "+":
                return 1;
            case "-":
                return 1;
            case "*":
                return 2;
            case "/":
                return 2;
            default:
                throw new RuntimeException("没有该类型的运算符!");
        }
    }

}

输入中缀表达式为:1+((2+3)×4)-5。测试结果如下:
在这里插入图片描述
后缀表达式的特点就是计算机运算非常方便,需要用到栈;计算机处理过程只需要顺序读入,如果遇到数字,则放入栈中,如果是运算符,则将两个栈中数字取出进行运算;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值