【数据结构】计算机是如何进行四则混合运算

我们在数学中常见的计算式,例如9 + ( 3 - 1 ) * 3 + 10 / 2。表达式中涉及到了多个运算符,而运算符之间是有优先级的,而计算器没法理解,因为计算机只会按照输入的运算符一个一个的进行计算。

为了避开运算优先级的问题,计算机常采用前、后缀表达式来处理。那么前、后缀表达式为什么能避开优先级的问题,接着看正文。

一、定义

1.1、中缀表达式

定义:一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。

9 + ( 3 - 1 ) * 3 + 10 / 2
1.2、后缀表达式

后缀表达式,又称逆波兰式,指的是不包含括号,运算符放在两个运算对象的后面(例:3 4 +),所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)

9 3 1 - 3 * + 10 2 / +
1.3、前缀表达式

前缀表达式就是不含括号的算术表达式,而且它是将运算符写在前面(例:+ 3 4), 操作数写在后面的表达式,也称为“波兰式”

二、中缀表达式转后缀表达式

这里我们需要用到栈的结构,转换规则是:

数字输出,运算符进栈,括号匹配出栈,栈顶优先级低出栈

以“9 + ( 3 - 1 ) * 3 + 10 / 2”为例

2.1、数字9输出

数字直接输出

image-20220127202810611
2.2、运算符+(进栈

遇到运算符进栈(要求栈顶优先级高)

image-20220127202810611
2.3、括号匹配出栈

遇到")“,输出”( -"

image-20220127202810611
2.4、栈顶优先级低出栈

要添加的*优先级高,需要先清空栈

image-20220127202810611
2.5、清空栈

清空剩余的+ /

image-20220127202810611

三、后缀表达式的计算

后缀表达式运算规则是碰到数字入栈,碰到运算符则取出栈中的两个元素做运算,并将结果再次入栈

仍以“9 3 1 - 3 * + 10 2 / +”为例

步骤1:9

步骤2:9 3

步骤3:9 3 1

这时候遇到"-",计算3-1

步骤4:9 2

步骤5:9 2 3

这时候遇到"x",计算2x3

步骤6:9 6

这时候遇到"+",计算9+6

步骤7:15

步骤8:15 10

步骤9:15 10 2

这时候遇到"/",计算10/2

步骤10:15 5

这时候遇到"+",计算15+5

步骤11:20

四、java运行demo

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        /**
         * 中缀表达式 9 + ( 3 - 1 ) * 3 + 10 / 2 = 20
         * 后缀表达式 9 3 1 - 3 * + 10 2 / +
         */
        String[] infixExpression = {"9", "+", "(", "3", "-", "1", ")", "*", "3", "+", "10", "/", "2"};
        String[] postfixExpression = convert(infixExpression);

        // 打印转换的后缀表达式
        System.out.print("后缀表达式:");
        for (int i = 0; i < postfixExpression.length; i++) {
            System.out.print(postfixExpression[i] + " ");
        }
        System.out.println();

        // 打印后缀表达式的计算结果
        String result = calculateResult(postfixExpression);
        System.out.println("后缀表达式计算结果:" + result);
    }

    // 中缀表达式转后缀表达式
    // 数字输出,运算符进栈,括号匹配出栈,栈顶优先级低出栈
    private static String[] convert(String[] expressArr) {
        Stack<String> stack = new Stack<>();
        List<String> result = new ArrayList<>();
        for (int i = 0; i < expressArr.length; i++) {
            Pattern patternNumber = Pattern.compile("([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])");
            if (patternNumber.matcher(expressArr[i]).matches()) {
                // 数字输出
                result.add(expressArr[i]);
            } else if (Arrays.asList(new String[]{"+", "-", "*", "/", "(", ")"}).contains(expressArr[i])) {
                if (expressArr[i].equals(")")) {
                    // 括号匹配出栈
                    while (!stack.peek().equals("(")) {
                        result.add(stack.pop());
                    }
                    stack.pop();
                } else {
                    boolean a = Arrays.asList(new String[]{"+", "-"}).contains(expressArr[i]);
                    boolean b = !stack.isEmpty() && Arrays.asList(new String[]{"*", "/"}).contains(stack.peek());
                    if (a && b) {
                        // 栈顶优先级低出栈
                        while (!stack.isEmpty()) {
                            result.add(stack.pop());
                        }
                        stack.push(expressArr[i]);
                    } else {
                        // 运算符进栈
                        stack.push(expressArr[i]);
                    }
                }
            }
        }
        // 剩余出栈
        while (!stack.isEmpty()) {
            result.add(stack.pop());
        }
        return result.toArray(new String[0]);
    }

    // 计算后缀表达式结果
    private static String calculateResult(String[] expressArr) {
        Stack<String> stack = new Stack<>();
        for (int i = 0; i < expressArr.length; i++) {
            switch (expressArr[i]) {
                case "+":
                    String A = stack.pop();
                    String B = stack.pop();
                    stack.push((Double.parseDouble(B) + Double.parseDouble(A)) + "");
                    break;
                case "-":
                    A = stack.pop();
                    B = stack.pop();
                    stack.push((Double.parseDouble(B) - Double.parseDouble(A)) + "");
                    break;
                case "*":
                    A = stack.pop();
                    B = stack.pop();
                    stack.push((Double.parseDouble(B) * Double.parseDouble(A)) + "");
                    break;
                case "/":
                    A = stack.pop();
                    B = stack.pop();
                    stack.push((Double.parseDouble(B) / Double.parseDouble(A)) + "");
                    break;
                default:
                    stack.push(expressArr[i]);
                    break;
            }
        }
        return stack.pop();
    }
}

运算结果

image-20220127202810611
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值