• 中缀表达式转后缀表达式并计算结果


    1 栈的概念

    容器,先进后出规则;如图为表达式:a+(b*c) 逐个操作符、操作数入栈过程;出栈为该过程逆序

    2 何谓中缀表达式

    型如:a - b + c 的普通算术表达式,我们称之为中缀表达式。

    3 后缀表达式(逆波兰)

    3.1 概念以及案例

    中缀表达式:a - b + c ,转化为后缀表达式:ab-c+;

    后缀表达式运算规则:

    1. 遇到操作数直接入栈,遇到操作符,从栈顶弹出两个操作数,并计算如下表达式结果压栈,直至最终弹出栈中最后一个数即停止算法,该记法的表达式称为后缀表达式

      后出栈操作数(两数中更靠近栈底者) (操作符[+_*/]) 先出栈操作数(栈顶)

    2. ab-c+计算过程如下图:

    3.2 求解方法

    入栈优先级

    { [ ( > = > =

    3.2.1 流程图

    • 弹出案例:扫描位优先级较小,扫描位为 " - "。

    • 左括号虽然优先级大,但是左括号只在碰到,匹配的右括号时弹出

    3.2.2 推导相等优先级为何弹出栈顶

    只关注相同有优先级下是否弹出栈顶

    • 先加,后加减
    中缀表达式 后缀表达式
    a + b + c abc++ 或 ab+c+
    a + b - c ab+c- 或 abc-+

    此例中,当需要判断操作符间优先级:栈顶为:+(加),栈外判断位:+ 或 - 。 此时若优先级相等,既可弹出栈顶操作符,也可不弹直接当前位压栈。

    • 先减,后加减
    中缀表达式 后缀表达式
    a - b + c ab-c+
    a - b - c ab-c-

    此例中,当需要判断操作符间优先级:栈顶为:-(减),栈外判断位:+ 或 - 。 此时若优先级相等,则只能弹出当前栈顶操作符。

    • 先乘,后乘除
    中缀表达式 后缀表达式
    a * b * c abc** 或 abc
    a * b / c abc/ 或 abc/

    此例中,当需要判断操作符间优先级:栈顶为:(乘),栈外判断位: 或 / 。 此时若优先级相等,既可弹出栈顶操作符,也可不弹直接当前位压栈。

    • 先除,后乘除
    中缀表达式 后缀表达式
    a / b * c ab/c*
    a / b / c ab/c/

    此例中,当需要判断操作符间优先级:栈顶为:/(除),栈外判断位: * 或 / 。 此时若优先级相等,则只能弹出当前栈顶操作符。

    对比上述4种情景,取其交集,故在当前位等于栈顶优先级时,弹出栈顶。

    3.2.3 案例

    • 中缀表达式:2{1+2[4/(8-6)+7]}

    下图为推推导过程,其中对部分直接入栈操作、或直接输出的操作进行了省略:

    • 后缀表达式:2 1 2 4 8 6 - / 7 + * + *

    代码

    实际代码与推导过程略有差异,做了两个处理

    1. 负数前加 0,例如 -5 * 3 转为 0 - 5 * 3

    2. 读取连续数字,推导过程中使用的都是单个操作数,但是实际使用时肯定有多位数的操作,所以当读取到一个数字位时,则判断下一位是否为数字,读出连续数字。

    
    import java.util.*;
    import java.lang.*;
    public class Main {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("\r\n输入一个合法中缀表达式:");
            while (scanner.hasNextLine()) {
                // 1.读取一行输入
                String nextLine = scanner.nextLine();
                List<String> express = new ArrayList<>();// 后缀表达式容器
                // 2.中缀转后缀
                handle(nextLine, express);
                System.out.print("后缀表达式:" + express);
                // 3.计算后缀表达式结果并输出
                execute(express);
                System.out.println("\r\n输入一个合法中缀表达式:");
            }
        }
    
        private static void handle(String nextLine, List<String> express) {
            Stack<Character> opt = new Stack<>();// 保存操作符
            int index = 0;
            while (index < nextLine.length()) {
                char c = nextLine.charAt(index);
                if (c == '-' && (index == 0 || getPower(nextLine.charAt(index -1)) == 10)) {// 含负数算式:-2*5, 转为: 0-2*5
                    express.add(String.valueOf('0'));
                }
                if (c >= '0' && c <= '9') {// 一或多个连续数字
                    StringBuilder tempSpace = new StringBuilder().append(c);
                    while (index < nextLine.length() - 1 && (c = nextLine.charAt(index + 1)) >= '0' && c <= '9') {
                        tempSpace.append(c);
                        ++index;
                    }
                    express.add(tempSpace.toString());
                    ++index;
                } else {
                    if (opt.isEmpty()) {
                        opt.push(c);
                    } else {
                        int power_c = getPower(c);
                        int power_top = getPower(opt.peek());
                        if (power_top == 10) {// 左括号
                            opt.push(c);
                        } else if (power_c == -10) {
                            while (!opt.isEmpty() && 10 != getPower(opt.peek())) {// 右括号,弹出所有操作符,直到遇到左括号为止
                                express.add(String.valueOf(opt.pop()));
                            }
                            if (!opt.isEmpty() && getPower(opt.peek()) == 10) opt.pop();// 弹出与之配对左括号
                        } else {// 四则运算符
                            if (power_top >= power_c) { // 栈顶优先级大于或等于当前位时, 弹出栈内元素直至遇到一个优先级相等的为止
                                while (!opt.isEmpty() && getPower(opt.peek()) < 10  && getPower(opt.peek()) >= power_c ) {
                                    power_top = getPower(opt.peek());
                                    express.add(String.valueOf(opt.pop()));
                                    if (power_top == power_c) break;
                                }
                            }
                            opt.push(c);
                        }
                    }
                    ++index;
                }
            }
            while (!opt.isEmpty()) {
                if (getPower(opt.peek()) != 10 && getPower(opt.peek()) != -10)
                    express.add(String.valueOf(opt.pop()));
            }
        }
    
        private static void execute(List<String> express) {
            int index = 0;
            Stack<Integer> temp = new Stack<>();
            while (index < express.size()) {
                String c = express.get(index);
                char currentOpt = c.charAt(0);
                if (c.length() > 1 ||  currentOpt >= '0' && currentOpt <= '9')
                    temp.push(Integer.parseInt(c));
                else {
                    int right = temp.pop();
                    int left = temp.pop();
                    if (currentOpt == '+') {
                        temp.push(left + right);
                    } else if (currentOpt == '-') {
                        temp.push(left - right);
                    } else if (currentOpt == '*') {
                        temp.push(left * right);
                    } else if (currentOpt == '/') {
                        temp.push(left / right);
                    }
                }
                ++index;
            }
            System.out.println("   计算结果:" + temp.pop());
        }
    
        public static int getPower(char c) {
            if (c == '{' || c == '[' || c == '(') {
                return 10;
            } else if (c == '*' || c == '/') {
                return 3;
            } else if (c == '+' || c == '-') {
                return 1;
            } else if (c == ')' || c == ']' || c == '}') {
                return -10;
            }
            return Integer.MIN_VALUE;
        }
    
    }
    
    
    • 部分测试用例:

        3*5+8-0*3-6+0+0
        5-3+9*6*(6-10-2)       # 连续数字
        3-10+(0+(10+5+3)-10)   # 连续数字
        3+2*{1+2*[-4/(8-6)+7]} # 含负数
        3+2*{1+2*[4/(8-6)+7]}
      
    • 输出

  • 相关阅读:
    存储过程加密
    sql 指删除表,改表名,改字段名
    windows 2003 server 64 位 IIS 6下部署 32位网站
    linux查看内存的使用占比
    linux查看端口是否被占用
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock' (2)
    mysql数据库的备份(mysqldump)和恢复(source)
    linux解压压缩文件zip/tar/tar.gz命令汇总
    oracle数据库的备份和导入数据
    oracle 备份表数据
  • 原文地址:https://www.cnblogs.com/bokers/p/15942351.html
Copyright © 2020-2023  润新知