计算器算法实现java

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37681914/article/details/79458788

测试类:

package com.fly.design.calculate;

import org.junit.Test;

import static org.junit.Assert.*;

/**
 * @author weijun.zou
 * Create on 2018/3/6
 */
public class ExpressionTest {
    @Test
    public void calculate() throws Exception {
        assertEquals(-6, Expression.calculate("((4+5)-(3*4))*2").intValue());
        assertEquals(0, Expression.calculate("5%5").intValue());
        assertEquals(-1000, Expression.calculate("-(3+3+4)^(3*(2-1))").intValue());
    }

}

算法:

package com.fly.design.calculate;

import com.fly.design.calculate.utils.ArrayStack;
import com.fly.design.calculate.utils.Stack;

import java.util.Objects;

/**
 * @author weijun.zou
 * Create on 2018/3/6
 */
public class Expression {

    private static final char LEFT_BRACKET = '(';
    private static final char RIGHT_BRACKET = ')';
    private static final char MINUS = '-';
    private static final char SPACE = ' ';

    /**
     * 将一个表达式计算出结果
     *
     * @param expressString 表达式
     * @return 数字
     */
    public static Number calculate(String expressString) {
        Objects.requireNonNull(expressString);
        int capacity = expressString.length() / 4;
        Stack<Integer> leftBracketStack = new ArrayStack<>(capacity);
        int index = 0;
        String bracketString = expressString;
        for (char symbol : expressString.toCharArray()) {
            if (symbol == LEFT_BRACKET) {
                leftBracketStack.push(index);
                index++;
            } else if (symbol == RIGHT_BRACKET) {
                /*
                 * 计算括号里的值
                 */
                int rightBracket = index;
                int leftBracket = leftBracketStack.pop();
                String simpleExpress = bracketString.substring(leftBracket + 1, rightBracket);
                Number number = calculate(new NumberElement(simpleExpress));
                String value = number.toString();
                /*
                 * 简化括号表达式
                 */
                bracketString = bracketString.substring(0, leftBracket)
                        + value
                        + bracketString.substring(rightBracket + 1);
                index = leftBracket + value.length();
            } else {
                index++;
            }
        }
        return calculate(new NumberElement(bracketString));
    }

    private static Number calculate(NumberElement root) {
        Objects.requireNonNull(root);
        /*
         * 从左至右,根据操作符的优先级计算
         */
        Stack<NumberElement> stack = new ArrayStack<>();
        stack.push(root);
        NumberElement nextElement = root.nextElement;

        while (Objects.nonNull(nextElement)) {
            NumberElement numberElement = stack.pop();
            //判断当前numberElement的操作符是否可以优先计算
            if (Operator.priority(numberElement.preOperator, nextElement.preOperator)) {
                //获取element的操作符左边的数
                NumberElement preNumber = stack.pop();
                //将合并后的新的操作数存入栈中
                stack.push(merge(preNumber, numberElement));
            } else {
                stack.push(numberElement);
                stack.push(nextElement);
                nextElement = nextElement.nextElement;
            }
        }
        NumberElement result = stack.pop();
        while (!stack.isEmpty()) {
            NumberElement preNumber = stack.pop();
            result = merge(preNumber, result);
        }
        return result.number;
    }

    private static NumberElement merge(NumberElement preNumber, NumberElement numberElement) {
        Objects.requireNonNull(preNumber);
        Objects.requireNonNull(numberElement);
        Number number = numberElement.preOperator.calculate(preNumber.number, numberElement.number);
        return new NumberElement(preNumber.preOperator, number.doubleValue(), numberElement.nextElement);
    }

    private static class NumberElement {
        //前置操作符
        private Operator preOperator;
        //数字
        private double number;
        //下一个操作数
        private NumberElement nextElement;

        NumberElement(Operator preOperator, double number, NumberElement nextElement) {
            this.preOperator = preOperator;
            this.number = number;
            this.nextElement = nextElement;
        }

        NumberElement() {

        }

        NumberElement(String string) {
            Objects.requireNonNull(string);
            char[] chars = string.trim().toCharArray();
            int index = 0;
            NumberElement tail = new NumberElement();
            tail.nextElement = this;
            while (index < chars.length) {
                if (chars[index] == SPACE) {
                    index++;
                    continue;
                }
                Operator preOperator = null;
                //获取数字之前的操作符,但不包括负号
                if (index > 0 && Operator.isOperator(String.valueOf(chars[index]))) {
                    preOperator = Operator.get(String.valueOf(chars[index]));
                    index++;
                }
                //获取数字
                int cursor;
                for (cursor = index; cursor < chars.length; cursor++) {
                    //负号
                    if (cursor == index && chars[cursor] == MINUS) continue;
                    //操作符
                    if (Operator.isOperator(String.valueOf(chars[cursor]))) {
                        break;
                    }
                }
                double number = Double.valueOf(string.substring(index, cursor));
                tail = tail.nextElement;
                tail.preOperator = preOperator;
                tail.number = number;
                tail.nextElement = new NumberElement();
                index = cursor;
            }
            tail.nextElement = null;
        }
    }
}
package com.fly.design.calculate;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;

import static java.util.stream.Collectors.toMap;

/**
 * @author weijun.zou
 * Create on 2018/2/11
 * 运算符
 */
public enum Operator {

    ADDITION("+", 0, (a, b) -> a.doubleValue() + b.doubleValue()),
    SUBTRACTION("-", 0, (a, b) -> a.doubleValue() - b.doubleValue()),
    MULTIPLICATION("*", 10, (a, b) -> a.doubleValue() * b.doubleValue()),
    DIVISION("/", 10, (a, b) -> a.doubleValue() / b.doubleValue()),
    MODULUS("%", 10, (a, b) -> a.doubleValue() % b.doubleValue()),
    POWER("^", 100, (a, b) -> Math.pow(a.doubleValue(), b.doubleValue())),

    DEFAULT(null, Integer.MAX_VALUE, true, (a, b) -> {
        throw new RuntimeException("该运算符不存在");
    });

    private static Map<String, Operator> operatorMap =
            Arrays.stream(Operator.values())
                    .collect(toMap(Operator::getSymbol, operator -> operator));

    /**
     * null false
     * notnull null true
     * notnull notnull 比较priority、相等再看isLeftOrder
     */
    public static boolean priority(Operator operator, Operator contrast) {
        //operator为null一律为false
        if (Objects.isNull(operator)) {
            return false;
        }
        /* true:
         * 后者为null
         * 前者priority大于后者
         * 相等且从左到右的顺序
         */
        return Objects.isNull(contrast)
                || operator.priority > contrast.priority
                || (operator.priority == contrast.priority && operator.isLeftOrder());
    }


    public static boolean isOperator(String operator) {
        return operatorMap.containsKey(operator);
    }

    public static Operator get(String symbol) {
        return operatorMap.getOrDefault(symbol, DEFAULT);
    }

    private BiFunction<Number, Number, Number> function;
    private String symbol;
    private int priority;
    private boolean isLeftOrder;

    Operator(String symbol, int priority, BiFunction<Number, Number, Number> function) {
        this.symbol = symbol;
        this.priority = priority;
        isLeftOrder = true;
        this.function = function;
    }

    Operator(String symbol, int priority, boolean isLeftOrder, BiFunction<Number, Number, Number> function) {
        this.symbol = symbol;
        this.priority = priority;
        this.isLeftOrder = isLeftOrder;
        this.function = function;
    }

    public Number calculate(Number a, Number b) {
        return function.apply(a, b);
    }

    public String getSymbol() {
        return symbol;
    }

    @Override
    public String toString() {
        return symbol;
    }

    public boolean isLeftOrder() {
        return isLeftOrder;
    }
}
package com.fly.design.calculate.utils;

import java.util.List;

/**
 * @author weijun.zou
 * Create on 2018/2/17
 */
public interface Stack<E> {
    E push(E item);
    E pop();
    boolean isEmpty();
    List<E> toList();
}
package com.fly.design.calculate.utils;


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

/**
 * @author weijun.zou
 * Create on 2018/2/17
 */
public class ArrayStack<E> implements Stack<E> {

    private List<E> list ;

    public ArrayStack() {
        list = new ArrayList<>();
    }

    public ArrayStack(int capacity){
        list = new ArrayList<>(capacity);
    }

    @Override
    public E push(E item) {
        boolean success = list.add(item);
        if (success) {
            return item;
        } else {
            throw new RuntimeException("push item failed");
        }
    }

    @Override
    public E pop() {
        if (list.isEmpty()) {
            throw new RuntimeException("pop failed, none item");
        } else {
            return list.remove(list.size() - 1);
        }
    }

    @Override
    public List<E> toList() {
        return new ArrayList<>(list);
    }

    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37681914/article/details/79458788