通过后缀表达式进行算数表达式求值(栈的应用)

这是一道面试时遇到的题目,那时没答出来,之后查了相关资料。在这里将自己对于这个问题的理解做下记录,之后便于查阅。

题目:给定一个算数表达式,用程序进行算数表达式求值。比如求解1×2+6×(3-4÷5)。

思路:先用运算符栈将常见的中缀表达式转化为后缀表达式(逆波兰表达式)。再通过操作数栈进行后缀表达式的求值。

后缀表达式:操作数在前,运算符在后,且运算符按优先级从高到低排序。

运算符有+,-,×,÷,(,)。其中‘×’,‘÷’的优先级高于‘+’,‘-’的优先级;‘(’的优先级大于之前所有运算符的优先级,小于之后所有运算符的优先级。‘)’无所谓优先级,碰到’)‘时需要将运算符栈中’(‘之上的运算符弹出来,最后将’('也弹出来。其中,同优先级的运算符,先出现运算符的优先级高。

  1. 将中缀表达式转化为后缀表达式

    下面描述下将常见的中缀表达式转换成后缀表达式的做法:从前到后扫描算数表达式。如果是数字,直接添加到后缀表达式的最后。如果是运算符且运算符栈为空时,将运算符添加到运算符栈中。如果运算符栈不为空,需要进行多情况处理

    (1)如果是’+’,’-‘运算符,它们的优先级只比’(‘高,所以需要不断弹出运算符栈中的运算符,直到栈为空或者栈顶为’('运算符;

    (2)如果是’×’,‘÷’运算符,它们的优先级比’(‘、’+’、’-‘高,所以需要不断弹出运算符栈中的运算符,直到栈为空或者栈顶为’(’、’+‘,’-'运算符;

    (3)如果是’('运算符,直接入栈;

    (4)如果是’)‘运算符,不断弹出运算符,直到栈顶为’(’,将’('运算符弹出;

  2. 求解后缀表达式

    得到后缀表达式之后,通过操作数栈就可以计算后缀表达式的值。具体做法为:从头到尾扫描后缀表达式,如果是操作数,入栈;如果是运算符,弹出两个操作数,先弹出的为右操作数,后弹出的为左操作数,计算完之后将结果入栈。扫描完之后,栈中的结果即为表达值的值。

下面是具体的代码(Java实现):

import java.util.Scanner;
import java.util.Stack;

/**
 * 数学表达式求值
 * 思路:
 * 先用栈转换成后缀表达式,然后用栈对后缀表达式求值
 * @Author CHT
 */
public class Main {
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        String expression = null;
        while (true){
            expression = scanner.next();
            System.out.println(String.format("%.2f",new Main().resultOfMathematicalExpression(expression)));
        }
    }
    /**
     * 根据后缀表达式计算结果
     * @param mathematicalExpression
     * @return
     */
    private double resultOfMathematicalExpression(String mathematicalExpression){
        String postExpression = postMathematicalExpression(mathematicalExpression);
        String[] strings = postExpression.split("#");
        Stack<Double> operandStack = new Stack<>();
        double operandLeft = 0,operandRight = 0;
        for (String string:strings) {
            switch (string){
                case "+":{
                    operandRight = operandStack.pop();
                    operandLeft = operandStack.pop();
                    operandStack.push(operandLeft+operandRight);
                    break;
                }
                case "-":{
                    operandRight = operandStack.pop();
                    operandLeft = operandStack.pop();
                    operandStack.push(operandLeft-operandRight);
                    break;
                }
                case "*":{
                    operandRight = operandStack.pop();
                    operandLeft = operandStack.pop();
                    operandStack.push(operandLeft*operandRight);
                    break;
                }
                case "/":{
                    operandRight = operandStack.pop();
                    operandLeft = operandStack.pop();
                    operandStack.push(operandLeft/operandRight);
                    break;
                }
                default:
                    operandStack.push(Double.parseDouble(string));
            }
        }
        return operandStack.pop();
    }

    /**
     * 将中缀表达式转换成后缀表达式。用'#'分隔
     * @param mathematicalExpression
     * @return
     */
    private String postMathematicalExpression(String mathematicalExpression){
        //后缀表达式
        StringBuilder postExpression = new StringBuilder();
        //操作符栈
        Stack<Character> operatorStack = new Stack<>();
        //数字直接添加到后缀表达式,运算符按照优先级从高到低排序
        for (int i = 0; i < mathematicalExpression.length(); i++) {
            //0~9直接添加到后缀表达式
            if (mathematicalExpression.charAt(i)>='0' && mathematicalExpression.charAt(i)<='9'){
                postExpression.append(mathematicalExpression.charAt(i));

            }//'+' '-' 运算符的优先级只比 '(' 高
            else if (mathematicalExpression.charAt(i)=='+' || mathematicalExpression.charAt(i)=='-'){
                postExpression.append('#');
                if (operatorStack.empty() || operatorStack.peek()=='('){
                    operatorStack.push(mathematicalExpression.charAt(i));
                }else {
                    while (!operatorStack.empty() && operatorStack.peek()!='('){
                        postExpression.append(operatorStack.pop()).append('#');
                    }
                    operatorStack.push(mathematicalExpression.charAt(i));
                }
            }//'*' '/'的优先级比 '+' '-' '('高
            else if (mathematicalExpression.charAt(i)=='*' || mathematicalExpression.charAt(i)=='/'){
                postExpression.append('#');
                if (operatorStack.empty() || operatorStack.peek()=='(' || operatorStack.peek()=='+' || operatorStack.peek()=='-'){
                    operatorStack.push(mathematicalExpression.charAt(i));
                }else {
                    while (!operatorStack.empty() && operatorStack.peek()!='(' && operatorStack.peek()!='+' && operatorStack.peek()!='-'){
                        postExpression.append(operatorStack.pop()).append('#');
                    }
                    operatorStack.push(mathematicalExpression.charAt(i));
                }
            }// '('的优先级比前面的运算符都高,比后面的运算符优先级低
            else if (mathematicalExpression.charAt(i)=='('){
                operatorStack.push(mathematicalExpression.charAt(i));
            }// 碰到')',将'('之前的运算符弹出,最后将'('弹出
            else if (mathematicalExpression.charAt(i)==')'){
                postExpression.append('#');
                while (operatorStack.peek()!='('){
                    postExpression.append(operatorStack.pop()).append('#');
                }
                postExpression.deleteCharAt(postExpression.length()-1);
                operatorStack.pop();
            }
        }
        while (!operatorStack.empty()){
            postExpression.append("#").append(operatorStack.pop());
        }
        return postExpression.toString();
    }

参考:

https://blog.csdn.net/smile_zhangw/article/details/82916346

https://blog.csdn.net/qq_40395874/article/details/79904233

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值