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;
        }
    }

    运行结果

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

  • 相关阅读:
    java 在线网络考试系统源码 springboot mybaits vue.js 前后分离跨域
    springboot 整合flowable 项目源码 mybiats vue.js 前后分离 跨域
    flowable Springboot vue.js 前后分离 跨域 有代码生成器 工作流
    Flowable 工作流 Springboot vue.js 前后分离 跨域 有代码生成器
    java 企业 网站源码 后台 springmvc SSM 前台 静态化 代码生成器
    java 进销存 商户管理 系统 管理 库存管理 销售报表springmvc SSM项目
    基于FPGA的电子计算器设计(中)
    基于FPGA的电子计算器设计(上)
    FPGA零基础学习:SPI 协议驱动设计
    Signal tap 逻辑分析仪使用教程
  • 原文地址:https://www.cnblogs.com/ftx3q/p/15715418.html
Copyright © 2011-2022 走看看