zoukankan      html  css  js  c++  java
  • 数据结构之栈实现中缀转后缀并计算结果

    一.中缀变后缀过程分析

    给定一个中缀,最后变为后缀的过程其实并不算复杂,下面分析一下过程:

    1. 首先面对一个中缀表达式,我们需要两个栈,一个用来存放运算符,即符号栈 operatorstack,一个用来存放数字,运算符,即数字栈 numStack

    2. 开始扫描中缀表达式

    3.遇到操作数时,我们直接压入数字栈,即numStack;

    4.遇到运算符时,需要我们比较一下当前符号与栈顶符号的优先级,这里分以下三种情况

      4.1 operatorStack为空,好的,我们直接压入

      4.2 operatorStack不为空,且当前符号的优先级大于栈顶符号的优先级,我们也直接压入符号栈

      4.3 operatorStack不为空,且当前符号的优先级小于或者等于栈顶符号的优先级,这是我们需要先将operatorStack的栈顶pop出并push到numStack,此处是一个while循环,直到找出当前符号的优先级大于符号栈栈顶符    号的优先级为止,再将当前符号压入operatorStack.

    5.遇到括号时,有如下操作

      5.1 如果是  "("  ,直接压入符号栈.operatorStack;

      5.2 如果是  ")"  ,则将符号栈栈内符号依次弹出,push进numStack,直到遇见  "("  为止,注意的是,这一对括号进入丢弃状态,即  "(" 弹出,不会入任何栈,")" 也不会入任何栈

    6.重复2-5,扫描中缀表达式,直到最后结束

    7.最后将符号栈中符号顺序弹出并加入数字栈

    8.数字栈numStack输出,结果的逆序就是我们要的后缀表达式

    二. 代码实现

    通过一中的过程分析我们可以看到,数字栈从头到输出之前并没有进行任何弹栈操作,所以为了便于书写,下面将数字栈采用arrayList来代替,且易于输出

    并且,如果采用索引去对中队表达式进行扫描的话,会十分麻烦,所以我们采用以下思路,进行转换并计算结果

    中缀表达式 -->顺序存放中缀表达式中数字,操作符以及括号的list集合 --> 根据上面一的思路转成存放后缀表达式的元素的集合 rearList-->遍历rearList进行计算

    代码如下:

    package com.ebiz.stack;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Stack;
    
    /**
     * @author YHj
     * @create 2019-07-24 15:51
     *
     * 中缀表达式转后缀表达式
     */
    public class MiddleToRear {
    
        public static void main(String[] args) {
            //不用索引扫描表达式,将表达式加入到list中
            String expression="1+((2+3)*4)-5";
            //得到中缀表达式转为list的集合
            List<String> list=getList(expression);
            //将中缀表达式的集合转到后缀表达式的集合
            List<String> rearList=getRearList(list);
            System.out.println("rearList = " + rearList);
    
            //输出计算结果
            System.out.println(getResult(rearList));
    
    
    }
    
        //中缀表达式的集合转为后缀表达式的集合
        private static List<String> getRearList(List<String> list) {
            ArrayList<String> rearList = new ArrayList<>();
            //定义符号栈
            Stack<String> operatorStack = new Stack<>();
            //定义集合代替数字栈,数字栈本身并没有pop操作,并且最后要倒叙输出,随意用list代替
            ArrayList<String> numList = new ArrayList<>();
            for (String s : list) {
                //如果是个数字
                if (s.matches("\d+")){
                    numList.add(s);
                }else if (s.equals("(")){
                    operatorStack.push(s);
                }else if (s.equals(")")){
                    //符号栈栈顶直到左括号之前的符号放入数字栈
                    while (!"(".equals(operatorStack.peek())){
                        numList.add(operatorStack.pop());
                    }
                    //把左括号弹出来
                    operatorStack.pop();
                //判断优先级,当前符号优先级小于等于符号栈栈顶优先级,将符号栈栈顶弹出加入数字栈,
                //直到找到当前符号优先级大于符号栈栈顶优先级为止,再将当前符号加入符号栈
                }else{
                    while (operatorStack.size()!=0 && (OperPriority.getPriority(s) <= OperPriority.getPriority(operatorStack.peek()))){
                        numList.add(operatorStack.pop());
                    }
                    //将当前符号加入符号栈
                    operatorStack.push(s);
                }
            }
            //将符号栈中剩余符号加入数字栈
            while (operatorStack.size()!=0){
                numList.add(operatorStack.pop());
            }
            return numList;
        }
    
        //将中缀表达式的各个字符存到list集合,方面遍历
        private static List<String> getList(String expression) {
            ArrayList<String> list = new ArrayList<>();
            int index=0;
            String str=""; //多位数的拼接
            char c;  //用于存放每次扫描到的结果
            do {
                //判断是否为数字,非数字直接加入list
                c=expression.charAt(index);
                if (c < 48 || c >57){
                    list.add(""+c);
                }else {//数字.考虑可能不是一位数,字符串拼接
                    str+=c;
                    if (index == expression.length()-1){
                        list.add(str);
                    }else {
                        if (expression.charAt(index+1) < 48 || expression.charAt(index+1) > 57){
                            list.add(str);
                            str="";
                        }
                    }
                }
                index++;
            }while (index < expression.length());
            return list;
        }
        //输出计算结果
        private static int getResult(List<String> list) {
            Stack<String> stack = new Stack<>();
            for (String s : list) {
                //匹配数字
                if (s.matches("\d+")){
                    stack.push(s);
                }else {
                    int num01=Integer.parseInt(stack.pop());
                    int num02=Integer.parseInt(stack.pop());
                    int result=0;
                    if (s.equals("+")){
                        result=num01+num02;
                    }else if (s.equals("-")){
                        result=num02-num01;
                    }else if (s.equals("*")){
                        result=num02*num01;
                    }else if (s.equals("/")){
                        result=num02/num01;
                    }else {
                        throw new RuntimeException("无法解析的字符串");
                    }
                    stack.push(""+result);
                }
            }
            return Integer.parseInt(stack.pop());
        }
    
    
    }

     上面涉及到的判断符号优先级的类

    package com.ebiz.stack;
    
    /**
     * @author YHj
     * @create 2019-07-24 18:14
     */
    public class OperPriority {
        private static int AAD =1; //加;
        private static int SUB =1; //
        private static int MUL =2; //
        private static int DIV =2; //
    
    
        public static int getPriority(String operator){
            int result=0;
            switch (operator){
                case "+":
                    result=AAD;
                    break;
                case "-":
                    result=SUB;
                    break;
                case "*":
                    result=MUL;
                    break;
                case "/":
                    result=DIV;
                    break;
                default:
                    break;
            }
            return result;
        }
    
    
    }

    有待完善...

  • 相关阅读:
    系统分析员、系统架构师、项目经理的区别
    C# 委托(Delegate) 事件(Event)应用详解
    项目管理的通俗解释
    什么是依赖注入
    程序员每天该做的事
    鸿蒙应用开发入门(三):开发第一个鸿蒙应用
    #2020征文手机# 零基础鸿蒙开发4 如何播放一个全屏视频(JS版)
    【资源下载】快来获取HarmonyOS官方通用规范图标
    #2020征文手机# 快速搭建一款鸿蒙分布式分歧终端机原型
    #2020征文TV#鸿蒙应用开发TVHelloWord (二) 传递数据、跳转
  • 原文地址:https://www.cnblogs.com/jiushixihuandaqingtian/p/11241370.html
Copyright © 2011-2022 走看看