计算器算法实现java
2018-03-06 15:16
471 查看
测试类:
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(); } }
相关文章推荐
- 用java实现了一个小的计算器算法
- 计算器核心算法代码实现(Java)
- MD5 算法的java实现
- 中国农历算法java实现(转自Herong Yang)
- Java中的几种算法的实现
- Java中的几种算法的实现
- 用java实现人工智能中的A*算法求8数码问题
- AIX 程序设计大赛-AIX正方形问题算法及Java程序实现
- java实现的18位身份证格式验证算法
- AIX 程序设计大赛-AIX正方形问题算法及Java程序实现(方案三)
- 通过Java实现一种常用的权限控制算法
- java归并算法实现
- 用java实现的素数第二种算法
- 用Java实现归并排序(Merge-Sort)算法
- 上楼梯算法的java实现(转)
- 在java中实现图形学中的椭圆算法
- java窗口的实现---计算器(算加法)
- Java和C#摘要算法实现
- AIX 程序设计大赛-AIX正方形问题算法及Java程序实现(方案二)
- java实现的18位身份证格式验证算法