欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java 实现字符串四则运算

程序员文章站 2022-03-31 11:07:03
...

手痒写写抄抄代码,看来需要好好复习下算法了。

一、测试代码

package cn.dt.algorithm.stack;

import org.junit.Assert;
import org.junit.Test;

/**
 * @author DT
 * @date 2020/7/28 14:43
 */

public class InfixExpressionTest {

    @Test
    public void testCalculator() {
        InfixExpression infixExpression = new InfixExpression();
        Assert.assertEquals(3 + 2 * 6 - 5 / 1, infixExpression.calculate("3 + 2 * 6 - 5 / 1"));
        Assert.assertEquals(3 + 2, infixExpression.calculate("3 + 2"));
        Assert.assertEquals(3 - 2, infixExpression.calculate("3 - 2"));
        Assert.assertEquals(3 * 2, infixExpression.calculate("3 * 2"));
        Assert.assertEquals(3 / 2, infixExpression.calculate("3 / 2"));
        Assert.assertEquals(30 + 2 * 6, infixExpression.calculate("30 + 2 * 6"));
        Assert.assertEquals(30 * 2 + 6, infixExpression.calculate("30 * 2 + 6"));
    }
}

二、实现

1. 表达式处理类

package cn.dt.algorithm.stack;

import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;

/**
 * 表达式处理类
 * 解析表达式,并使用计数器计算解析结果。
 *
 * @author DT
 * @date 2020/7/28 13:25
 */
public class InfixExpression {

    /**
     * 表达式中数值与符号使用空格分隔
     */
    private static final char SPLITTER = ' ';


    /**
     * 计算表达式的值
     *
     * @param expression 表达式,数值与符号之间是要空格隔开
     * @return
     */
    public int calculate(String expression) {


        Calculator calculator = new Calculator();

        String[] strings = StringUtils.split(expression, SPLITTER);

        Arrays.stream(strings).forEach(s -> handleString(calculator, s));

        return calculator.getResult();
    }


    /**
     * 处理字符,数字和操作数分开处理。
     * 当出现非数字和四则运算符试抛出 @UnsupportedOperationException 异常
     *
     * @param calculator
     * @param s
     */
    private void handleString(Calculator calculator, String s) {

        if (isNumber(s)) {
            calculator.addNum(Integer.valueOf(s));
        } else if (isOperator(s)) {
            calculator.addOperator(s);
        } else {
            throw new UnsupportedOperationException("非法字符:" + s);
        }
    }

    /**
     * 判断字符串是否是操作符
     *
     * @param s 字符
     * @return 字符为四则运算符时返回 true
     */
    private boolean isOperator(String s) {
        return "+".equals(s) || "-".equals(s) || "*".equals(s) || "/".equals(s);
    }

    /**
     * 判断是否是数字
     *
     * @param s 字符
     * @return 如果是数字返回 true
     */
    private boolean isNumber(String s) {
        return s.matches("\\d+");
    }
}

2. 计算类

/**
 * 计算器,实现四则运算
 *
 * @author DT
 * @date 2020/7/28 15:33
 */
public class Calculator {

    /**
     * 定义四则运算*别, “*” 和 “/"
     */
    public static final int MAX_PRIORITY = 2;

    /**
     * 数值栈,用于存放操作数
     */
    private Stack<Integer> numStack = new Stack<>();

    /**
     * 操作符栈, 用于存放操作符
     */
    private Stack<String> operatorStack = new Stack<>();

    public int getResult() {

        while (!operatorStack.isEmpty()) {
            calc();
        }

        return numStack.pop();
    }

    /**
     * 从数值栈和操作符栈中取值进行计算, 并将结果压入操作数栈
     */
    private void calc() {

        int    num2     = numStack.pop();
        int    num1     = numStack.pop();
        String operator = operatorStack.pop();

        int result = 0;

        switch (operator) {
            case "+":
                result = num1 + num2;
                break;
            case "-":
                result = num1 - num2;
                break;
            case "*":
                result = num1 * num2;
                break;
            case "/":
                result = num1 / num2;
                break;
            default:
                throw new UnsupportedOperationException("非法操作符:" + operator);
        }

        numStack.push(result);
    }

    /**
     * 获取操作数栈栈顶元素优先级
     *
     * @return 栈顶元素优先级
     */
    private int getTopOperatorPriority() {

        if (operatorStack.isEmpty()) {
            return 0;
        }

        String s = operatorStack.peek();

        return getOperatorPriority(s);
    }

    /**
     * 获取操作符优先级
     *
     * @param s 操作符
     * @return "+" ”-“ 返回 1,”*“ ”/" 返回 2. 否则抛出 @UnsupportedOperationException
     */
    private int getOperatorPriority(String s) {

        if ("+".equals(s) || "-".equals(s)) {
            return 1;
        } else if ("*".equals(s) || "/".equals(s)) {
            return 2;
        } else {
            throw new UnsupportedOperationException("非法操作符:" + s);
        }
    }

    /**
     * 处理操作符
     * 1. 如果操作数栈顶是最高优先级( “*”、“/"), 进行计算
     * 2. 如果操作数栈不为空,且栈顶元素与当前操作符同级,进行计算
     * 3. 将操作符入栈
     *
     * @param s
     */
    public void addOperator(String s) {

        if (!operatorStack.isEmpty() && getOperatorPriority(s) != MAX_PRIORITY) {
            calc();
        }

        operatorStack.push(s);
    }

    /**
     * 处理数值,将数值入栈
     * <p>
     * 然后判断下操作符栈顶元素,如果是*进行计算。
     *
     * @param num
     */
    public void addNum(Integer num) {

        numStack.push(num);

        if (getTopOperatorPriority() == MAX_PRIORITY) {
            calc();
        }
    }
}

参考

这位大哥写的清晰明了, 请移步 ——— 数据结构-栈的应用之中缀表达式的计算