Java中缀表达式转后缀表达式并计算后缀表达式的值

Posted Spring-_-Bear

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中缀表达式转后缀表达式并计算后缀表达式的值相关的知识,希望对你有一定的参考价值。

一、中缀表达式转后缀表达式的思路分析

从左到右开始扫描中缀表达式:

  1. 遇到数字,直接输出

  2. 遇到运算符:

    2.1 若为左括号 “(” 或栈为空则 直接入栈
    2.2 若为右括号 “)” 将符号栈中的元素依次出栈并输出, 直到左括号 “(“ 出栈, “(“ 只出栈不输出
    2.3 若为其他符号, 将符号栈中的元素依次出栈并输出, 直到遇到比当前符号优先级更低的符号,并将当前符号入栈

  3. 扫描完后, 将符号栈栈中剩余符号依次输出

二、中缀表达式转后缀表达式的代码实现

    /**
     * 将中缀表达式转换为后缀表达式,生成的后缀表达式各元素之间使用一个空格间隔
     *
     * @param infixExp 中缀表达式
     * @return 后缀表达式 或 null
     */
    public String infixToSuffix(String infixExp) 
        if (infixExp == null || infixExp.length() == 0) 
            return null;
        

        Stack<String> operatorStack = new Stack<>();
        List<String> infixList = infixExpIntoList(infixExp);
        StringBuilder res = new StringBuilder();
        // 从左至右遍历中缀表达式
        for (String str : infixList) 
            // 如果是数字则直接输出
            if (str.matches("\\\\d+")) 
                res.append(str).append(" ");
             else if ("(".equals(str) || operatorStack.size() == 0) 
                // 左括号或栈为空则直接入栈
                operatorStack.push(str);
             else if (")".equals(str)) 
                // 右括号需要将符号栈中的 "(" 括号之前的操作符全部输出,"(" 只出栈不输出
                String op;
                while (!"(".equals((op = operatorStack.pop()))) 
                    res.append(op).append(" ");
                
             else 
                // 栈顶操作符优先级大于等于当前操作符,则弹出栈顶元素,结束后将当前操作符压入栈中
                while (operatorStack.size() > 0 && getPriority(operatorStack.peek()) - getPriority(str) >= 0) 
                    res.append(operatorStack.pop()).append(" ");
                
                operatorStack.push(str);
            
        

        // 将符号栈中剩余的操作符输出
        while (operatorStack.size() > 0) 
            res.append(operatorStack.pop()).append(" ");
        
        return res.toString();
    

三、对后缀表达式进行计算的思路分析

后缀表达式的特点是运算符位于与其相关的操作数之后。计算机求值步骤如下:

  1. 从左至右扫描后缀表达式
  2. 遇到数字将其压入栈中
  3. 遇到操作符则从栈中弹出两个操作数并计算,将计算结果再次压入栈中
  4. 如此往复直至扫描完整个表达式
  5. 弹出栈中剩余的数即为运算结果

四、后缀表达式运算的代码实现

    /**
     * 计算后缀表达式,要求传入的后缀表达式各操作符与操作数之间以空格间隔
     *
     * @param suffixExp 后缀表达式
     * @return 计算结果
     */
    public int calSuffixExp(String suffixExp) 
        String[] suffix = suffixExp.split(" ");
        Stack<Integer> numStack = new Stack<>();
        // 从左至右遍历后缀表达式
        for (String str : suffix) 
            // 遇到数字则将其压入栈中
            if (str.matches("\\\\d+")) 
                numStack.push(Integer.valueOf(str));
             else 
                // 遇到操作符则从栈顶依次弹出两个操作数计算得到结果 res,并将 res 再次压入栈顶
                numStack.push(calculate(numStack.pop(), numStack.pop(), str));
            
        
        return numStack.pop();
    

五、中缀转后缀并求出运算结果完整版代码实现

package com.bear.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * @author Spring-_-Bear
 * @datetime 2022/3/11 9:29
 */
public class Calculator 

    /**
     * 计算后缀表达式,要求传入的后缀表达式各操作符与操作数之间以空格间隔
     *
     * @param suffixExp 后缀表达式
     * @return 计算结果
     */
    public int calSuffixExp(String suffixExp) 
        String[] suffix = suffixExp.split(" ");
        Stack<Integer> numStack = new Stack<>();
        // 从左至右遍历后缀表达式
        for (String str : suffix) 
            // 遇到数字则将其压入栈中
            if (str.matches("\\\\d+")) 
                numStack.push(Integer.valueOf(str));
             else 
                // 遇到操作符则从栈顶依次弹出两个操作数计算得到结果 res,并将 res 再次压入栈顶
                numStack.push(calculate(numStack.pop(), numStack.pop(), str));
            
        
        return numStack.pop();
    

    /**
     * 将中缀表达式转换为后缀表达式,生成的后缀表达式各元素之间使用一个空格间隔
     *
     * @param infixExp 中缀表达式
     * @return 后缀表达式 或 null
     */
    public String infixToSuffix(String infixExp) 
        if (infixExp == null || infixExp.length() == 0) 
            return null;
        

        Stack<String> operatorStack = new Stack<>();
        List<String> infixList = infixExpIntoList(infixExp);
        StringBuilder res = new StringBuilder();
        // 从左至右遍历中缀表达式
        for (String str : infixList) 
            // 如果是数字则直接输出
            if (str.matches("\\\\d+")) 
                res.append(str).append(" ");
             else if ("(".equals(str) || operatorStack.size() == 0) 
                // 左括号或栈为空则直接入栈
                operatorStack.push(str);
             else if (")".equals(str)) 
                // 右括号需要将符号栈中的 "(" 括号之前的操作符全部输出,"(" 只出栈不输出
                String op;
                while (!"(".equals((op = operatorStack.pop()))) 
                    res.append(op).append(" ");
                
             else 
                // 栈顶操作符优先级大于等于当前操作符,则弹出栈顶元素,结束后将当前操作符压入栈中
                while (operatorStack.size() > 0 && getPriority(operatorStack.peek()) - getPriority(str) >= 0) 
                    res.append(operatorStack.pop()).append(" ");
                
                operatorStack.push(str);
            
        

        // 将符号栈中剩余的操作符输出
        while (operatorStack.size() > 0) 
            res.append(operatorStack.pop()).append(" ");
        
        return res.toString();
    

    /**
     * 将中缀表达式各操作数、操作符元素分割添加到 List 中
     *
     * @param infixExp 中缀表达式
     * @return list 或 null
     */
    public List<String> infixExpIntoList(String infixExp) 
        if (infixExp == null || infixExp.length() == 0) 
            return null;
        

        int len = infixExp.length();
        List<String> infixList = new ArrayList<>();

        // 从左至右遍历中缀表达式,依次将操作数和操作符加入 List 中
        for (int i = 0; i < len; i++) 
            char ch = infixExp.charAt(i);
            // ASCII 码在 [48,57] 的为数字,将非数字加入到 List 中
            if (ch < 48 || ch > 57) 
                infixList.add(String.valueOf(ch));
                continue;
            

            // 将当前数字连接到数字字符串中
            String digitsStr = "" + ch;
            ++i;
            // 判断该数字接下来的字符是否是数字即是否是一个多位数
            while (i < len && infixExp.charAt(i) >= 48 && infixExp.charAt(i) <= 57) 
                digitsStr += infixExp.charAt(i);
                ++i;
            
            infixList.add(digitsStr);
            // 因为 while 循环中 ++i 语句和 for循环中的 i++ 语句使 i 多自增 1,故此处 --i
            --i;
        

        return infixList;
    

    /**
     * 获得运算符的优先级:加减运算优先级为 0,乘除运算优先级为 1
     *
     * @param operator 运算符
     * @return 运算符优先级代号
     */
    public int getPriority(String operator) 
        switch (operator) 
            case "+":
            case "-":
                return 1;
            case "*":
            case "/":
                return 2;
            default:
                return 0;
        
    

    /**
     * 计算两数运算结果
     *
     * @param num1     number
     * @param num2     number
     * @param operator operator
     * @return 运算结果
     */
    public Integer calculate(Integer num1, Integer num2, String operator) 
        switch (operator) 
            case "+":
                return num1 + num2;
            case "-":
                return num2 - num1;
            case "*":
                return num1 * num2;
            case "/":
                return num2 / num1;
            default:
                System.out.println("非法的操作符");
                return null;
        
    

以上是关于Java中缀表达式转后缀表达式并计算后缀表达式的值的主要内容,如果未能解决你的问题,请参考以下文章

中缀表达式转后缀表达式并计算

中缀表达式转后缀并计算(只考虑个位整数,不考虑除0等情况)

将中缀表达式转换成后缀表达式

堆栈入门-简单计算器模板-中缀转后缀

java实现中缀表达式转后缀表达式

中缀式转后缀式求表达式结果