zoukankan      html  css  js  c++  java
  • 中缀表达式转后缀表达式(代码实现)及前缀表达式思路补充

      后缀表达式适合计算机式的计算,因此在开发中,我们需要将中缀表达式转为后缀表达式。

    三种表达式

      这里再次区分一下前缀表达式、中缀表达式、后缀表达式(以(3+4)*5-6为例)

      中缀表达式就是我们正常遇见的(3+4)*5-6这样的式子

      前缀表达式又称为波兰式,其运算符是在数之前

      中缀表达式转前缀表达式思路:从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 top 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果

      例如:- * + 3 4 5 6

    1. 从右至左扫描,将6、5、4、3压入堆栈
    2. 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做比较),计算出3+4的值,得7,再将7入栈
    3. 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈
    4. 最后是-运算符,计算出35-6的值,即29,由此得出最终结果

    中缀表达式转后缀表达式具体步骤

        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.atxihua;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Stack;
    
    public class PolandNotation1 {
        public static void main(String[] args) {
            //完成将一个中缀表达式转成后缀表达式的功能
            //1+((2+3)*4)-5转成1 2 3 + 4 * + 5 -
            //因为直接对str进行操作,不方便,因此,先将1+((2+3)*4)-5存入对应的list
            //即1+((2+3)*4)-5=》ArrayList[1,+,(,(,2,+,3,),*,4),-,5]
            //将得到的中缀表达式对应的List=》后缀表达式对应的List
            //即ArrayList[1,+,(,(,2,+,3,),*,4),-,5]=>ArrayList[1,2,3,+,4,*,+,5,-]
            String expression="1+((2+3)*4)-5";
            List<String> infixExpreesionList=toInfixExpreesionList(expression);
            System.out.println("中缀表达式="+infixExpreesionList);//ArrayList[1,+,(,(,2,+,3,),*,4),-,5]
            List<String> suffixExpreesionList=parseSuffixExpreesionList(infixExpreesionList);
            System.out.println("后缀表达式="+suffixExpreesionList);//ArrayList[1,2,3,+,4,*,+,5,-]
            System.out.println("结果为:"+calculate(suffixExpreesionList));
        }
        //将中缀表达式转成对应的list
        private static List<String> toInfixExpreesionList(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){
                    ls.add(""+c);
                    i++;
                }else {//如果是一个数,需要考虑多位数
                    str="";//先将str设置为0[48]-9[57]
                    while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
                        str+=c;//拼接
                        i++;
                    }
                    ls.add(str);
                }
            }while (i<s.length());
            return ls;
        }
        //将得到的中缀表达式对应的List=>后缀表达式
        private static List<String> parseSuffixExpreesionList(List<String> ls) {
            //定义两个栈
            Stack<String> s1=new Stack<String>();//符号栈
            //说明:s2这个栈,在整个转换过程中,没有pop操作,而且后面需要逆序输出,就不使用栈,直接使用list存储
            //Stack<String> s2=new Stack<String>();//数栈
            List<String> s2=new ArrayList<String>();//存储中间结果的list
            //遍历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,直到遇到左括号为止,此时将这一对括号丢弃
                    //我们缺少一个比较优先级高低的方法
                    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;//
        }
    
    
        private static int calculate(List<String> ls) {
            //创建一个栈
            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("-")){
                        //注意num2比num1先出栈,所以是num1-num2
                        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());
        }
    }
    //编写一个类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;
            if(operation.equals("+")){
                result=Add;
            }else if(operation.equals("-")){
                result=SUB;
            }else if(operation.equals("*")){
                result=MUL;
            }else if(operation.equals("/")){
                result=DIV;
            }else {
                System.out.println("不存在该运算符");
            }
            return result;
        }
    }

    运行结果

     因为我们在写代码时,遇到左括号时,压入栈中,在遇到右括号时在处理,因此,计算机将左括号当作运算符处理,在处理逻辑中只对加减乘除进行了处理,相信这点很容易理解,就不再处理了。

  • 相关阅读:
    工具推荐-css3渐变生成工具
    IE6bug-overflow不能隐藏的bug
    cs3属性操作js
    多级联动下拉菜单(原生js)
    js表单验证大全
    js-运动框架(时间版)
    LeetCode 677. 键值映射
    LeetCode 28. Implement strStr()
    计网学习笔记(5)
    计网学习笔记(4)
  • 原文地址:https://www.cnblogs.com/ftx3q/p/15715418.html
Copyright © 2011-2022 走看看